jscript: Use jsval instead of VARIANT to pass arguments to builtin functions.
[wine] / dlls / jscript / engine.c
1 /*
2  * Copyright 2008,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 "config.h"
20 #include "wine/port.h"
21
22 #include <math.h>
23 #include <assert.h>
24
25 #include "jscript.h"
26 #include "engine.h"
27
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
31
32 static const WCHAR booleanW[] = {'b','o','o','l','e','a','n',0};
33 static const WCHAR functionW[] = {'f','u','n','c','t','i','o','n',0};
34 static const WCHAR numberW[] = {'n','u','m','b','e','r',0};
35 static const WCHAR objectW[] = {'o','b','j','e','c','t',0};
36 static const WCHAR stringW[] = {'s','t','r','i','n','g',0};
37 static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
38 static const WCHAR unknownW[] = {'u','n','k','n','o','w','n',0};
39
40 struct _except_frame_t {
41     unsigned stack_top;
42     scope_chain_t *scope;
43     unsigned catch_off;
44     BSTR ident;
45
46     except_frame_t *next;
47 };
48
49 static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v)
50 {
51     if(!ctx->stack_size) {
52         ctx->stack = heap_alloc(16*sizeof(VARIANT));
53         if(!ctx->stack)
54             return E_OUTOFMEMORY;
55         ctx->stack_size = 16;
56     }else if(ctx->stack_size == ctx->top) {
57         VARIANT *new_stack;
58
59         new_stack = heap_realloc(ctx->stack, ctx->stack_size*2*sizeof(VARIANT));
60         if(!new_stack) {
61             VariantClear(v);
62             return E_OUTOFMEMORY;
63         }
64
65         ctx->stack = new_stack;
66         ctx->stack_size *= 2;
67     }
68
69     ctx->stack[ctx->top++] = *v;
70     return S_OK;
71 }
72
73 static HRESULT stack_push_bool(exec_ctx_t *ctx, BOOL b)
74 {
75     VARIANT v;
76
77     V_VT(&v) = VT_BOOL;
78     V_BOOL(&v) = b ? VARIANT_TRUE : VARIANT_FALSE;
79     return stack_push(ctx, &v);
80 }
81
82 static inline HRESULT stack_push_number(exec_ctx_t *ctx, double number)
83 {
84     VARIANT v;
85
86     num_set_val(&v, number);
87     return stack_push(ctx, &v);
88 }
89
90 static inline HRESULT stack_push_int(exec_ctx_t *ctx, INT n)
91 {
92     VARIANT v;
93
94     V_VT(&v) = VT_I4;
95     V_I4(&v) = n;
96     return stack_push(ctx, &v);
97 }
98
99 static inline HRESULT stack_push_string(exec_ctx_t *ctx, const WCHAR *str)
100 {
101     VARIANT v;
102
103     V_VT(&v) = VT_BSTR;
104     V_BSTR(&v) = SysAllocString(str);
105     return V_BSTR(&v) ? stack_push(ctx, &v) : E_OUTOFMEMORY;
106 }
107
108 static HRESULT stack_push_objid(exec_ctx_t *ctx, IDispatch *disp, DISPID id)
109 {
110     VARIANT v;
111     HRESULT hres;
112
113     V_VT(&v) = VT_DISPATCH;
114     V_DISPATCH(&v) = disp;
115     hres = stack_push(ctx, &v);
116     if(FAILED(hres))
117         return hres;
118
119     V_VT(&v) = VT_INT;
120     V_INT(&v) = id;
121     return stack_push(ctx, &v);
122 }
123
124 static inline VARIANT *stack_top(exec_ctx_t *ctx)
125 {
126     assert(ctx->top);
127     return ctx->stack + ctx->top-1;
128 }
129
130 static inline VARIANT *stack_topn(exec_ctx_t *ctx, unsigned n)
131 {
132     assert(ctx->top > n);
133     return ctx->stack + ctx->top-1-n;
134 }
135
136 static inline VARIANT *stack_args(exec_ctx_t *ctx, unsigned n)
137 {
138     if(!n)
139         return NULL;
140     assert(ctx->top > n-1);
141     return ctx->stack + ctx->top-n;
142 }
143
144 static inline VARIANT *stack_pop(exec_ctx_t *ctx)
145 {
146     assert(ctx->top);
147     return ctx->stack + --ctx->top;
148 }
149
150 static void stack_popn(exec_ctx_t *ctx, unsigned n)
151 {
152     while(n--)
153         VariantClear(stack_pop(ctx));
154 }
155
156 static HRESULT stack_pop_number(exec_ctx_t *ctx, double *r)
157 {
158     VARIANT *v;
159     HRESULT hres;
160
161     v = stack_pop(ctx);
162     hres = to_number(ctx->script, v, ctx->ei, r);
163     VariantClear(v);
164     return hres;
165 }
166
167 static HRESULT stack_pop_object(exec_ctx_t *ctx, IDispatch **r)
168 {
169     VARIANT *v;
170     HRESULT hres;
171
172     v = stack_pop(ctx);
173     if(V_VT(v) == VT_DISPATCH) {
174         if(!V_DISPATCH(v))
175             return throw_type_error(ctx->script, ctx->ei, JS_E_OBJECT_REQUIRED, NULL);
176         *r = V_DISPATCH(v);
177         return S_OK;
178     }
179
180     hres = to_object(ctx->script, v, r);
181     VariantClear(v);
182     return hres;
183 }
184
185 static inline HRESULT stack_pop_int(exec_ctx_t *ctx, INT *r)
186 {
187     return to_int32_var(ctx->script, stack_pop(ctx), ctx->ei, r);
188 }
189
190 static inline HRESULT stack_pop_uint(exec_ctx_t *ctx, DWORD *r)
191 {
192     return to_uint32(ctx->script, stack_pop(ctx), ctx->ei, r);
193 }
194
195 static inline IDispatch *stack_pop_objid(exec_ctx_t *ctx, DISPID *id)
196 {
197     assert(V_VT(stack_top(ctx)) == VT_INT && V_VT(stack_topn(ctx, 1)) == VT_DISPATCH);
198
199     *id = V_INT(stack_pop(ctx));
200     return V_DISPATCH(stack_pop(ctx));
201 }
202
203 static inline IDispatch *stack_topn_objid(exec_ctx_t *ctx, unsigned n, DISPID *id)
204 {
205     assert(V_VT(stack_topn(ctx, n)) == VT_INT && V_VT(stack_topn(ctx, n+1)) == VT_DISPATCH);
206
207     *id = V_INT(stack_topn(ctx, n));
208     return V_DISPATCH(stack_topn(ctx, n+1));
209 }
210
211 static void exprval_release(exprval_t *val)
212 {
213     switch(val->type) {
214     case EXPRVAL_VARIANT:
215         if(V_VT(&val->u.var) != VT_EMPTY)
216             VariantClear(&val->u.var);
217         return;
218     case EXPRVAL_IDREF:
219         if(val->u.idref.disp)
220             IDispatch_Release(val->u.idref.disp);
221         return;
222     case EXPRVAL_INVALID:
223         return;
224     }
225 }
226
227 /* ECMA-262 3rd Edition    8.7.1 */
228 static HRESULT exprval_value(script_ctx_t *ctx, exprval_t *val, jsexcept_t *ei, VARIANT *ret)
229 {
230     V_VT(ret) = VT_EMPTY;
231
232     switch(val->type) {
233     case EXPRVAL_VARIANT:
234         return VariantCopy(ret, &val->u.var);
235     case EXPRVAL_IDREF:
236         if(!val->u.idref.disp) {
237             FIXME("throw ReferenceError\n");
238             return E_FAIL;
239         }
240
241         return disp_propget(ctx, val->u.idref.disp, val->u.idref.id, ret, ei);
242     case EXPRVAL_INVALID:
243         assert(0);
244     }
245
246     ERR("type %d\n", val->type);
247     return E_FAIL;
248 }
249
250 static HRESULT exprval_to_value(script_ctx_t *ctx, exprval_t *val, jsexcept_t *ei, VARIANT *ret)
251 {
252     if(val->type == EXPRVAL_VARIANT) {
253         *ret = val->u.var;
254         V_VT(&val->u.var) = VT_EMPTY;
255         return S_OK;
256     }
257
258     return exprval_value(ctx, val, ei, ret);
259 }
260
261 static void exprval_set_idref(exprval_t *val, IDispatch *disp, DISPID id)
262 {
263     val->type = EXPRVAL_IDREF;
264     val->u.idref.disp = disp;
265     val->u.idref.id = id;
266
267     if(disp)
268         IDispatch_AddRef(disp);
269 }
270
271 HRESULT scope_push(scope_chain_t *scope, jsdisp_t *jsobj, IDispatch *obj, scope_chain_t **ret)
272 {
273     scope_chain_t *new_scope;
274
275     new_scope = heap_alloc(sizeof(scope_chain_t));
276     if(!new_scope)
277         return E_OUTOFMEMORY;
278
279     new_scope->ref = 1;
280
281     IDispatch_AddRef(obj);
282     new_scope->jsobj = jsobj;
283     new_scope->obj = obj;
284
285     if(scope) {
286         scope_addref(scope);
287         new_scope->next = scope;
288     }else {
289         new_scope->next = NULL;
290     }
291
292     *ret = new_scope;
293     return S_OK;
294 }
295
296 static void scope_pop(scope_chain_t **scope)
297 {
298     scope_chain_t *tmp;
299
300     tmp = *scope;
301     *scope = tmp->next;
302     scope_release(tmp);
303 }
304
305 void scope_release(scope_chain_t *scope)
306 {
307     if(--scope->ref)
308         return;
309
310     if(scope->next)
311         scope_release(scope->next);
312
313     IDispatch_Release(scope->obj);
314     heap_free(scope);
315 }
316
317 HRESULT create_exec_ctx(script_ctx_t *script_ctx, IDispatch *this_obj, jsdisp_t *var_disp,
318         scope_chain_t *scope, BOOL is_global, exec_ctx_t **ret)
319 {
320     exec_ctx_t *ctx;
321
322     ctx = heap_alloc_zero(sizeof(exec_ctx_t));
323     if(!ctx)
324         return E_OUTOFMEMORY;
325
326     ctx->ref = 1;
327     ctx->is_global = is_global;
328
329     if(this_obj)
330         ctx->this_obj = this_obj;
331     else if(script_ctx->host_global)
332         ctx->this_obj = script_ctx->host_global;
333     else
334         ctx->this_obj = to_disp(script_ctx->global);
335     IDispatch_AddRef(ctx->this_obj);
336
337     jsdisp_addref(var_disp);
338     ctx->var_disp = var_disp;
339
340     script_addref(script_ctx);
341     ctx->script = script_ctx;
342
343     if(scope) {
344         scope_addref(scope);
345         ctx->scope_chain = scope;
346     }
347
348     *ret = ctx;
349     return S_OK;
350 }
351
352 void exec_release(exec_ctx_t *ctx)
353 {
354     if(--ctx->ref)
355         return;
356
357     if(ctx->scope_chain)
358         scope_release(ctx->scope_chain);
359     if(ctx->var_disp)
360         jsdisp_release(ctx->var_disp);
361     if(ctx->this_obj)
362         IDispatch_Release(ctx->this_obj);
363     if(ctx->script)
364         script_release(ctx->script);
365     heap_free(ctx->stack);
366     heap_free(ctx);
367 }
368
369 static HRESULT disp_get_id(script_ctx_t *ctx, IDispatch *disp, BSTR name, DWORD flags, DISPID *id)
370 {
371     IDispatchEx *dispex;
372     HRESULT hres;
373
374     hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
375     if(FAILED(hres)) {
376         TRACE("using IDispatch\n");
377
378         *id = 0;
379         return IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, id);
380     }
381
382     *id = 0;
383     hres = IDispatchEx_GetDispID(dispex, name, make_grfdex(ctx, flags|fdexNameCaseSensitive), id);
384     IDispatchEx_Release(dispex);
385     return hres;
386 }
387
388 static inline BOOL var_is_null(const VARIANT *v)
389 {
390     return V_VT(v) == VT_NULL || (V_VT(v) == VT_DISPATCH && !V_DISPATCH(v));
391 }
392
393 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, BOOL *ret)
394 {
395     IObjectIdentity *identity;
396     IUnknown *unk1, *unk2;
397     HRESULT hres;
398
399     if(disp1 == disp2) {
400         *ret = TRUE;
401         return S_OK;
402     }
403
404     if(!disp1 || !disp2) {
405         *ret = FALSE;
406         return S_OK;
407     }
408
409     hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
410     if(FAILED(hres))
411         return hres;
412
413     hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
414     if(FAILED(hres)) {
415         IUnknown_Release(unk1);
416         return hres;
417     }
418
419     if(unk1 == unk2) {
420         *ret = TRUE;
421     }else {
422         hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
423         if(SUCCEEDED(hres)) {
424             hres = IObjectIdentity_IsEqualObject(identity, unk2);
425             IObjectIdentity_Release(identity);
426             *ret = hres == S_OK;
427         }else {
428             *ret = FALSE;
429         }
430     }
431
432     IUnknown_Release(unk1);
433     IUnknown_Release(unk2);
434     return S_OK;
435 }
436
437 /* ECMA-262 3rd Edition    11.9.6 */
438 static HRESULT equal2_values(VARIANT *lval, VARIANT *rval, BOOL *ret)
439 {
440     TRACE("\n");
441
442     if(V_VT(lval) != V_VT(rval)) {
443         if(is_num_vt(V_VT(lval)) && is_num_vt(V_VT(rval)))
444             *ret = num_val(lval) == num_val(rval);
445         else if(var_is_null(lval))
446             *ret = var_is_null(rval);
447         else
448             *ret = FALSE;
449         return S_OK;
450     }
451
452     switch(V_VT(lval)) {
453     case VT_EMPTY:
454     case VT_NULL:
455         *ret = VARIANT_TRUE;
456         break;
457     case VT_I4:
458         *ret = V_I4(lval) == V_I4(rval);
459         break;
460     case VT_R8:
461         *ret = V_R8(lval) == V_R8(rval);
462         break;
463     case VT_BSTR:
464         if(!V_BSTR(lval))
465             *ret = !SysStringLen(V_BSTR(rval));
466         else if(!V_BSTR(rval))
467             *ret = !SysStringLen(V_BSTR(lval));
468         else
469             *ret = !strcmpW(V_BSTR(lval), V_BSTR(rval));
470         break;
471     case VT_DISPATCH:
472         return disp_cmp(V_DISPATCH(lval), V_DISPATCH(rval), ret);
473     case VT_BOOL:
474         *ret = !V_BOOL(lval) == !V_BOOL(rval);
475         break;
476     default:
477         FIXME("unimplemented vt %d\n", V_VT(lval));
478         return E_NOTIMPL;
479     }
480
481     return S_OK;
482 }
483
484 static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
485 {
486     named_item_t *item;
487     DISPID id;
488     HRESULT hres;
489
490     for(item = ctx->named_items; item; item = item->next) {
491         if(item->flags & SCRIPTITEM_GLOBALMEMBERS) {
492             hres = disp_get_id(ctx, item->disp, identifier, 0, &id);
493             if(SUCCEEDED(hres)) {
494                 if(ret)
495                     exprval_set_idref(ret, item->disp, id);
496                 return TRUE;
497             }
498         }
499     }
500
501     return FALSE;
502 }
503
504 /* ECMA-262 3rd Edition    10.1.4 */
505 static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
506 {
507     scope_chain_t *scope;
508     named_item_t *item;
509     DISPID id = 0;
510     HRESULT hres;
511
512     TRACE("%s\n", debugstr_w(identifier));
513
514     for(scope = ctx->exec_ctx->scope_chain; scope; scope = scope->next) {
515         if(scope->jsobj)
516             hres = jsdisp_get_id(scope->jsobj, identifier, fdexNameImplicit, &id);
517         else
518             hres = disp_get_id(ctx, scope->obj, identifier, fdexNameImplicit, &id);
519         if(SUCCEEDED(hres)) {
520             exprval_set_idref(ret, scope->obj, id);
521             return S_OK;
522         }
523     }
524
525     hres = jsdisp_get_id(ctx->global, identifier, 0, &id);
526     if(SUCCEEDED(hres)) {
527         exprval_set_idref(ret, to_disp(ctx->global), id);
528         return S_OK;
529     }
530
531     for(item = ctx->named_items; item; item = item->next) {
532         if((item->flags & SCRIPTITEM_ISVISIBLE) && !strcmpW(item->name, identifier)) {
533             if(!item->disp) {
534                 IUnknown *unk;
535
536                 if(!ctx->site)
537                     break;
538
539                 hres = IActiveScriptSite_GetItemInfo(ctx->site, identifier,
540                                                      SCRIPTINFO_IUNKNOWN, &unk, NULL);
541                 if(FAILED(hres)) {
542                     WARN("GetItemInfo failed: %08x\n", hres);
543                     break;
544                 }
545
546                 hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp);
547                 IUnknown_Release(unk);
548                 if(FAILED(hres)) {
549                     WARN("object does not implement IDispatch\n");
550                     break;
551                 }
552             }
553
554             ret->type = EXPRVAL_VARIANT;
555             V_VT(&ret->u.var) = VT_DISPATCH;
556             V_DISPATCH(&ret->u.var) = item->disp;
557             IDispatch_AddRef(item->disp);
558             return S_OK;
559         }
560     }
561
562     if(lookup_global_members(ctx, identifier, ret))
563         return S_OK;
564
565     ret->type = EXPRVAL_INVALID;
566     return S_OK;
567 }
568
569 static inline BSTR get_op_bstr(exec_ctx_t *ctx, int i){
570     return ctx->code->instrs[ctx->ip].u.arg[i].bstr;
571 }
572
573 static inline unsigned get_op_uint(exec_ctx_t *ctx, int i){
574     return ctx->code->instrs[ctx->ip].u.arg[i].uint;
575 }
576
577 static inline unsigned get_op_int(exec_ctx_t *ctx, int i){
578     return ctx->code->instrs[ctx->ip].u.arg[i].lng;
579 }
580
581 static inline const WCHAR *get_op_str(exec_ctx_t *ctx, int i){
582     return ctx->code->instrs[ctx->ip].u.arg[i].str;
583 }
584
585 static inline double get_op_double(exec_ctx_t *ctx){
586     return ctx->code->instrs[ctx->ip].u.dbl;
587 }
588
589 /* ECMA-262 3rd Edition    12.2 */
590 static HRESULT interp_var_set(exec_ctx_t *ctx)
591 {
592     const BSTR name = get_op_bstr(ctx, 0);
593     VARIANT *v;
594     jsval_t val;
595     HRESULT hres;
596
597     TRACE("%s\n", debugstr_w(name));
598
599     v = stack_pop(ctx);
600     hres = variant_to_jsval(v, &val);
601     VariantClear(v);
602     if(FAILED(hres))
603         return hres;
604
605     hres = jsdisp_propput_name(ctx->var_disp, name, val, ctx->ei);
606     jsval_release(val);
607     return hres;
608 }
609
610 /* ECMA-262 3rd Edition    12.6.4 */
611 static HRESULT interp_forin(exec_ctx_t *ctx)
612 {
613     const HRESULT arg = get_op_uint(ctx, 0);
614     IDispatch *var_obj, *obj = NULL;
615     IDispatchEx *dispex;
616     DISPID id, var_id;
617     BSTR name = NULL;
618     VARIANT *val;
619     HRESULT hres;
620
621     TRACE("\n");
622
623     val = stack_pop(ctx);
624
625     assert(V_VT(stack_top(ctx)) == VT_I4);
626     id = V_I4(stack_top(ctx));
627
628     var_obj = stack_topn_objid(ctx, 1, &var_id);
629     if(!var_obj) {
630         FIXME("invalid ref\n");
631         VariantClear(val);
632         return E_FAIL;
633     }
634
635     if(V_VT(stack_topn(ctx, 3)) == VT_DISPATCH)
636         obj = V_DISPATCH(stack_topn(ctx, 3));
637
638     if(obj) {
639         hres = IDispatch_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
640         if(SUCCEEDED(hres)) {
641             hres = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, id, &id);
642             if(hres == S_OK)
643                 hres = IDispatchEx_GetMemberName(dispex, id, &name);
644             IDispatchEx_Release(dispex);
645             if(FAILED(hres)) {
646                 VariantClear(val);
647                 return hres;
648             }
649         }else {
650             TRACE("No IDispatchEx\n");
651         }
652     }
653
654     if(name) {
655         VARIANT v;
656
657         VariantClear(val);
658
659         V_I4(stack_top(ctx)) = id;
660
661         V_VT(&v) = VT_BSTR;
662         V_BSTR(&v) = name;
663         hres = disp_propput(ctx->script, var_obj, var_id, &v, ctx->ei);
664         SysFreeString(name);
665         if(FAILED(hres))
666             return hres;
667
668         ctx->ip++;
669     }else {
670         stack_popn(ctx, 4);
671         ctx->ip = arg;
672         return stack_push(ctx, val);
673     }
674     return S_OK;
675 }
676
677 /* ECMA-262 3rd Edition    12.10 */
678 static HRESULT interp_push_scope(exec_ctx_t *ctx)
679 {
680     IDispatch *disp;
681     VARIANT *v;
682     HRESULT hres;
683
684     TRACE("\n");
685
686     v = stack_pop(ctx);
687     hres = to_object(ctx->script, v, &disp);
688     VariantClear(v);
689     if(FAILED(hres))
690         return hres;
691
692     hres = scope_push(ctx->scope_chain, to_jsdisp(disp), disp, &ctx->scope_chain);
693     IDispatch_Release(disp);
694     return hres;
695 }
696
697 /* ECMA-262 3rd Edition    12.10 */
698 static HRESULT interp_pop_scope(exec_ctx_t *ctx)
699 {
700     TRACE("\n");
701
702     scope_pop(&ctx->scope_chain);
703     return S_OK;
704 }
705
706 /* ECMA-262 3rd Edition    12.13 */
707 static HRESULT interp_case(exec_ctx_t *ctx)
708 {
709     const unsigned arg = get_op_uint(ctx, 0);
710     VARIANT *v;
711     BOOL b;
712     HRESULT hres;
713
714     TRACE("\n");
715
716     v = stack_pop(ctx);
717     hres = equal2_values(stack_top(ctx), v, &b);
718     VariantClear(v);
719     if(FAILED(hres))
720         return hres;
721
722     if(b) {
723         stack_popn(ctx, 1);
724         ctx->ip = arg;
725     }else {
726         ctx->ip++;
727     }
728     return S_OK;
729 }
730
731 /* ECMA-262 3rd Edition    12.13 */
732 static HRESULT interp_throw(exec_ctx_t *ctx)
733 {
734     TRACE("\n");
735
736     ctx->ei->var = *stack_pop(ctx);
737     return DISP_E_EXCEPTION;
738 }
739
740 static HRESULT interp_throw_ref(exec_ctx_t *ctx)
741 {
742     const HRESULT arg = get_op_uint(ctx, 0);
743
744     TRACE("%08x\n", arg);
745
746     return throw_reference_error(ctx->script, ctx->ei, arg, NULL);
747 }
748
749 static HRESULT interp_throw_type(exec_ctx_t *ctx)
750 {
751     const HRESULT hres = get_op_uint(ctx, 0);
752     const WCHAR *str = get_op_str(ctx, 1);
753
754     TRACE("%08x %s\n", hres, debugstr_w(str));
755
756     return throw_type_error(ctx->script, ctx->ei, hres, str);
757 }
758
759 /* ECMA-262 3rd Edition    12.14 */
760 static HRESULT interp_push_except(exec_ctx_t *ctx)
761 {
762     const unsigned arg1 = get_op_uint(ctx, 0);
763     const BSTR arg2 = get_op_bstr(ctx, 1);
764     except_frame_t *except;
765     unsigned stack_top;
766
767     TRACE("\n");
768
769     stack_top = ctx->top;
770
771     if(!arg2) {
772         HRESULT hres;
773
774         hres = stack_push_bool(ctx, TRUE);
775         if(FAILED(hres))
776             return hres;
777         hres = stack_push_bool(ctx, TRUE);
778         if(FAILED(hres))
779             return hres;
780     }
781
782     except = heap_alloc(sizeof(*except));
783     if(!except)
784         return E_OUTOFMEMORY;
785
786     except->stack_top = stack_top;
787     except->scope = ctx->scope_chain;
788     except->catch_off = arg1;
789     except->ident = arg2;
790     except->next = ctx->except_frame;
791     ctx->except_frame = except;
792     return S_OK;
793 }
794
795 /* ECMA-262 3rd Edition    12.14 */
796 static HRESULT interp_pop_except(exec_ctx_t *ctx)
797 {
798     except_frame_t *except;
799
800     TRACE("\n");
801
802     except = ctx->except_frame;
803     assert(except != NULL);
804
805     ctx->except_frame = except->next;
806     heap_free(except);
807     return S_OK;
808 }
809
810 /* ECMA-262 3rd Edition    12.14 */
811 static HRESULT interp_end_finally(exec_ctx_t *ctx)
812 {
813     VARIANT *v;
814
815     TRACE("\n");
816
817     v = stack_pop(ctx);
818
819     assert(V_VT(stack_top(ctx)) == VT_BOOL);
820     if(!V_BOOL(stack_top(ctx))) {
821         TRACE("passing exception\n");
822
823         VariantClear(v);
824         stack_popn(ctx, 1);
825         ctx->ei->var = *stack_pop(ctx);
826         return DISP_E_EXCEPTION;
827     }
828
829     stack_popn(ctx, 2);
830     return stack_push(ctx, v);
831 }
832
833 /* ECMA-262 3rd Edition    13 */
834 static HRESULT interp_func(exec_ctx_t *ctx)
835 {
836     unsigned func_idx = get_op_uint(ctx, 0);
837     jsdisp_t *dispex;
838     VARIANT v;
839     HRESULT hres;
840
841     TRACE("%d\n", func_idx);
842
843     hres = create_source_function(ctx->script, ctx->code, ctx->func_code->funcs+func_idx,
844             ctx->scope_chain, &dispex);
845     if(FAILED(hres))
846         return hres;
847
848     var_set_jsdisp(&v, dispex);
849     return stack_push(ctx, &v);
850 }
851
852 /* ECMA-262 3rd Edition    11.2.1 */
853 static HRESULT interp_array(exec_ctx_t *ctx)
854 {
855     VARIANT v, *namev;
856     IDispatch *obj;
857     DISPID id;
858     BSTR name;
859     HRESULT hres;
860
861     TRACE("\n");
862
863     namev = stack_pop(ctx);
864
865     hres = stack_pop_object(ctx, &obj);
866     if(FAILED(hres)) {
867         VariantClear(namev);
868         return hres;
869     }
870
871     hres = to_string(ctx->script, namev, ctx->ei, &name);
872     VariantClear(namev);
873     if(FAILED(hres)) {
874         IDispatch_Release(obj);
875         return hres;
876     }
877
878     hres = disp_get_id(ctx->script, obj, name, 0, &id);
879     SysFreeString(name);
880     if(SUCCEEDED(hres)) {
881         hres = disp_propget(ctx->script, obj, id, &v, ctx->ei);
882     }else if(hres == DISP_E_UNKNOWNNAME) {
883         V_VT(&v) = VT_EMPTY;
884         hres = S_OK;
885     }
886     IDispatch_Release(obj);
887     if(FAILED(hres))
888         return hres;
889
890     return stack_push(ctx, &v);
891 }
892
893 /* ECMA-262 3rd Edition    11.2.1 */
894 static HRESULT interp_member(exec_ctx_t *ctx)
895 {
896     const BSTR arg = get_op_bstr(ctx, 0);
897     IDispatch *obj;
898     VARIANT v;
899     DISPID id;
900     HRESULT hres;
901
902     TRACE("\n");
903
904     hres = stack_pop_object(ctx, &obj);
905     if(FAILED(hres))
906         return hres;
907
908     hres = disp_get_id(ctx->script, obj, arg, 0, &id);
909     if(SUCCEEDED(hres)) {
910         V_VT(&v) = VT_EMPTY;
911         hres = disp_propget(ctx->script, obj, id, &v, ctx->ei);
912     }else if(hres == DISP_E_UNKNOWNNAME) {
913         V_VT(&v) = VT_EMPTY;
914         hres = S_OK;
915     }
916     IDispatch_Release(obj);
917     if(FAILED(hres))
918         return hres;
919
920     return stack_push(ctx, &v);
921 }
922
923 /* ECMA-262 3rd Edition    11.2.1 */
924 static HRESULT interp_memberid(exec_ctx_t *ctx)
925 {
926     const unsigned arg = get_op_uint(ctx, 0);
927     VARIANT *objv, *namev;
928     IDispatch *obj;
929     BSTR name;
930     DISPID id;
931     HRESULT hres;
932
933     TRACE("%x\n", arg);
934
935     namev = stack_pop(ctx);
936     objv = stack_pop(ctx);
937
938     hres = to_object(ctx->script, objv, &obj);
939     VariantClear(objv);
940     if(SUCCEEDED(hres)) {
941         hres = to_string(ctx->script, namev, ctx->ei, &name);
942         if(FAILED(hres))
943             IDispatch_Release(obj);
944     }
945     VariantClear(namev);
946     if(FAILED(hres))
947         return hres;
948
949     hres = disp_get_id(ctx->script, obj, name, arg, &id);
950     SysFreeString(name);
951     if(FAILED(hres)) {
952         IDispatch_Release(obj);
953         if(hres == DISP_E_UNKNOWNNAME && !(arg & fdexNameEnsure)) {
954             obj = NULL;
955             id = JS_E_INVALID_PROPERTY;
956         }else {
957             return hres;
958         }
959     }
960
961     return stack_push_objid(ctx, obj, id);
962 }
963
964 /* ECMA-262 3rd Edition    11.2.1 */
965 static HRESULT interp_refval(exec_ctx_t *ctx)
966 {
967     IDispatch *disp;
968     VARIANT v;
969     DISPID id;
970     HRESULT hres;
971
972     TRACE("\n");
973
974     disp = stack_topn_objid(ctx, 0, &id);
975     if(!disp)
976         return throw_reference_error(ctx->script, ctx->ei, JS_E_ILLEGAL_ASSIGN, NULL);
977
978     hres = disp_propget(ctx->script, disp, id, &v, ctx->ei);
979     if(FAILED(hres))
980         return hres;
981
982     return stack_push(ctx, &v);
983 }
984
985 static HRESULT convert_args(exec_ctx_t *ctx, unsigned argc, jsval_t **ret)
986 {
987     VARIANT *args = stack_args(ctx, argc);
988     jsval_t *argv;
989     unsigned i;
990     HRESULT hres;
991
992     if(!argc) {
993         *ret = NULL;
994         return S_OK;
995     }
996
997     argv = heap_alloc(argc * sizeof(jsval_t));
998     if(!argv)
999         return E_OUTOFMEMORY;
1000
1001     for(i=0; i<argc; i++) {
1002         hres = variant_to_jsval(args+i, argv+i);
1003         if(FAILED(hres)) {
1004             while(i--)
1005                 jsval_release(argv[i]);
1006             heap_free(argv);
1007             return hres;
1008         }
1009     }
1010
1011     *ret = argv;
1012     return S_OK;
1013 }
1014
1015 /* ECMA-262 3rd Edition    11.2.2 */
1016 static HRESULT interp_new(exec_ctx_t *ctx)
1017 {
1018     const unsigned argc = get_op_uint(ctx, 0);
1019     VARIANT *constr, v;
1020     jsval_t r, *argv;
1021     unsigned i;
1022     HRESULT hres;
1023
1024     TRACE("%d\n", argc);
1025
1026     constr = stack_topn(ctx, argc);
1027
1028     /* NOTE: Should use to_object here */
1029
1030     if(V_VT(constr) == VT_NULL)
1031         return throw_type_error(ctx->script, ctx->ei, JS_E_OBJECT_EXPECTED, NULL);
1032     else if(V_VT(constr) != VT_DISPATCH)
1033         return throw_type_error(ctx->script, ctx->ei, JS_E_INVALID_ACTION, NULL);
1034     else if(!V_DISPATCH(constr))
1035         return throw_type_error(ctx->script, ctx->ei, JS_E_INVALID_PROPERTY, NULL);
1036
1037     hres = convert_args(ctx, argc, &argv);
1038     if(FAILED(hres))
1039         return hres;
1040
1041     hres = disp_call_value(ctx->script, V_DISPATCH(constr), NULL, DISPATCH_CONSTRUCT, argc, argv, &r, ctx->ei);
1042     for(i=0; i < argc; i++)
1043         jsval_release(argv[i]);
1044     heap_free(argv);
1045     if(FAILED(hres))
1046         return hres;
1047
1048     hres = jsval_to_variant(r, &v);
1049     jsval_release(r);
1050     if(FAILED(hres))
1051         return hres;
1052
1053     stack_popn(ctx, argc+1);
1054     return stack_push(ctx, &v);
1055 }
1056
1057 /* ECMA-262 3rd Edition    11.2.3 */
1058 static HRESULT interp_call(exec_ctx_t *ctx)
1059 {
1060     const unsigned argn = get_op_uint(ctx, 0);
1061     const int do_ret = get_op_int(ctx, 1);
1062     VARIANT v, *objv;
1063     jsval_t *argv, r;
1064     unsigned i;
1065     HRESULT hres;
1066
1067     TRACE("%d %d\n", argn, do_ret);
1068
1069     objv = stack_topn(ctx, argn);
1070     if(V_VT(objv) != VT_DISPATCH)
1071         return throw_type_error(ctx->script, ctx->ei, JS_E_INVALID_PROPERTY, NULL);
1072
1073     hres = convert_args(ctx, argn, &argv);
1074     if(FAILED(hres))
1075         return hres;
1076
1077     hres = disp_call_value(ctx->script, V_DISPATCH(objv), NULL, DISPATCH_METHOD, argn, argv,
1078             do_ret ? &r : NULL, ctx->ei);
1079     for(i=0; i < argn; i++)
1080         jsval_release(argv[i]);
1081     heap_free(argv);
1082     if(FAILED(hres))
1083         return hres;
1084
1085     stack_popn(ctx, argn+1);
1086
1087     if(!do_ret)
1088         return S_OK;
1089
1090     hres = jsval_to_variant(r, &v);
1091     jsval_release(r);
1092     if(FAILED(hres))
1093         return hres;
1094
1095     return stack_push(ctx, &v);
1096
1097 }
1098
1099 /* ECMA-262 3rd Edition    11.2.3 */
1100 static HRESULT interp_call_member(exec_ctx_t *ctx)
1101 {
1102     const unsigned argn = get_op_uint(ctx, 0);
1103     const int do_ret = get_op_int(ctx, 1);
1104     IDispatch *obj;
1105     jsval_t *argv;
1106     unsigned i;
1107     VARIANT v;
1108     DISPID id;
1109     HRESULT hres;
1110
1111     TRACE("%d %d\n", argn, do_ret);
1112
1113     obj = stack_topn_objid(ctx, argn, &id);
1114     if(!obj)
1115         return throw_type_error(ctx->script, ctx->ei, id, NULL);
1116
1117     hres = convert_args(ctx, argn, &argv);
1118     if(FAILED(hres))
1119         return hres;
1120
1121     hres = disp_call(ctx->script, obj, id, DISPATCH_METHOD, argn, argv, do_ret ? &v : NULL, ctx->ei);
1122     for(i=0; i < argn; i++)
1123         jsval_release(argv[i]);
1124     heap_free(argv);
1125     if(FAILED(hres))
1126         return hres;
1127
1128     stack_popn(ctx, argn+2);
1129     return do_ret ? stack_push(ctx, &v) : S_OK;
1130
1131 }
1132
1133 /* ECMA-262 3rd Edition    11.1.1 */
1134 static HRESULT interp_this(exec_ctx_t *ctx)
1135 {
1136     VARIANT v;
1137
1138     TRACE("\n");
1139
1140     V_VT(&v) = VT_DISPATCH;
1141     V_DISPATCH(&v) = ctx->this_obj;
1142     IDispatch_AddRef(ctx->this_obj);
1143     return stack_push(ctx, &v);
1144 }
1145
1146 /* ECMA-262 3rd Edition    10.1.4 */
1147 static HRESULT interp_ident(exec_ctx_t *ctx)
1148 {
1149     const BSTR arg = get_op_bstr(ctx, 0);
1150     exprval_t exprval;
1151     VARIANT v;
1152     HRESULT hres;
1153
1154     TRACE("%s\n", debugstr_w(arg));
1155
1156     hres = identifier_eval(ctx->script, arg, &exprval);
1157     if(FAILED(hres))
1158         return hres;
1159
1160     if(exprval.type == EXPRVAL_INVALID)
1161         return throw_type_error(ctx->script, ctx->ei, JS_E_UNDEFINED_VARIABLE, arg);
1162
1163     hres = exprval_to_value(ctx->script, &exprval, ctx->ei, &v);
1164     exprval_release(&exprval);
1165     if(FAILED(hres))
1166         return hres;
1167
1168     return stack_push(ctx, &v);
1169 }
1170
1171 /* ECMA-262 3rd Edition    10.1.4 */
1172 static HRESULT interp_identid(exec_ctx_t *ctx)
1173 {
1174     const BSTR arg = get_op_bstr(ctx, 0);
1175     const unsigned flags = get_op_uint(ctx, 1);
1176     exprval_t exprval;
1177     HRESULT hres;
1178
1179     TRACE("%s %x\n", debugstr_w(arg), flags);
1180
1181     hres = identifier_eval(ctx->script, arg, &exprval);
1182     if(FAILED(hres))
1183         return hres;
1184
1185     if(exprval.type == EXPRVAL_INVALID && (flags & fdexNameEnsure)) {
1186         DISPID id;
1187
1188         hres = jsdisp_get_id(ctx->script->global, arg, fdexNameEnsure, &id);
1189         if(FAILED(hres))
1190             return hres;
1191
1192         exprval_set_idref(&exprval, to_disp(ctx->script->global), id);
1193     }
1194
1195     if(exprval.type != EXPRVAL_IDREF) {
1196         WARN("invalid ref\n");
1197         exprval_release(&exprval);
1198         return stack_push_objid(ctx, NULL, JS_E_OBJECT_EXPECTED);
1199     }
1200
1201     return stack_push_objid(ctx, exprval.u.idref.disp, exprval.u.idref.id);
1202 }
1203
1204 /* ECMA-262 3rd Edition    7.8.1 */
1205 static HRESULT interp_null(exec_ctx_t *ctx)
1206 {
1207     VARIANT v;
1208
1209     TRACE("\n");
1210
1211     V_VT(&v) = VT_NULL;
1212     return stack_push(ctx, &v);
1213 }
1214
1215 /* ECMA-262 3rd Edition    7.8.2 */
1216 static HRESULT interp_bool(exec_ctx_t *ctx)
1217 {
1218     const int arg = get_op_int(ctx, 0);
1219
1220     TRACE("%s\n", arg ? "true" : "false");
1221
1222     return stack_push_bool(ctx, arg);
1223 }
1224
1225 /* ECMA-262 3rd Edition    7.8.3 */
1226 static HRESULT interp_int(exec_ctx_t *ctx)
1227 {
1228     const int arg = get_op_int(ctx, 0);
1229     VARIANT v;
1230
1231     TRACE("%d\n", arg);
1232
1233     V_VT(&v) = VT_I4;
1234     V_I4(&v) = arg;
1235     return stack_push(ctx, &v);
1236 }
1237
1238 /* ECMA-262 3rd Edition    7.8.3 */
1239 static HRESULT interp_double(exec_ctx_t *ctx)
1240 {
1241     const double arg = get_op_double(ctx);
1242
1243     TRACE("%lf\n", arg);
1244
1245     return stack_push_number(ctx, arg);
1246 }
1247
1248 /* ECMA-262 3rd Edition    7.8.4 */
1249 static HRESULT interp_str(exec_ctx_t *ctx)
1250 {
1251     const WCHAR *str = get_op_str(ctx, 0);
1252     VARIANT v;
1253
1254     TRACE("%s\n", debugstr_w(str));
1255
1256     V_VT(&v) = VT_BSTR;
1257     V_BSTR(&v) = SysAllocString(str);
1258     if(!V_BSTR(&v))
1259         return E_OUTOFMEMORY;
1260
1261     return stack_push(ctx, &v);
1262 }
1263
1264 /* ECMA-262 3rd Edition    7.8 */
1265 static HRESULT interp_regexp(exec_ctx_t *ctx)
1266 {
1267     const WCHAR *source = get_op_str(ctx, 0);
1268     const unsigned flags = get_op_uint(ctx, 1);
1269     jsdisp_t *regexp;
1270     VARIANT v;
1271     HRESULT hres;
1272
1273     TRACE("%s %x\n", debugstr_w(source), flags);
1274
1275     hres = create_regexp(ctx->script, source, strlenW(source), flags, &regexp);
1276     if(FAILED(hres))
1277         return hres;
1278
1279     var_set_jsdisp(&v, regexp);
1280     return stack_push(ctx, &v);
1281 }
1282
1283 /* ECMA-262 3rd Edition    11.1.4 */
1284 static HRESULT interp_carray(exec_ctx_t *ctx)
1285 {
1286     const unsigned arg = get_op_uint(ctx, 0);
1287     jsdisp_t *array;
1288     VARIANT *v, r;
1289     jsval_t val;
1290     unsigned i;
1291     HRESULT hres;
1292
1293     TRACE("%u\n", arg);
1294
1295     hres = create_array(ctx->script, arg, &array);
1296     if(FAILED(hres))
1297         return hres;
1298
1299     i = arg;
1300     while(i--) {
1301         v = stack_pop(ctx);
1302         hres = variant_to_jsval(v, &val);
1303         if(SUCCEEDED(hres)) {
1304             hres = jsdisp_propput_idx(array, i, val, ctx->ei);
1305             jsval_release(val);
1306         }
1307         VariantClear(v);
1308         if(FAILED(hres)) {
1309             jsdisp_release(array);
1310             return hres;
1311         }
1312     }
1313
1314     var_set_jsdisp(&r, array);
1315     return stack_push(ctx, &r);
1316 }
1317
1318 /* ECMA-262 3rd Edition    11.1.5 */
1319 static HRESULT interp_new_obj(exec_ctx_t *ctx)
1320 {
1321     jsdisp_t *obj;
1322     VARIANT v;
1323     HRESULT hres;
1324
1325     TRACE("\n");
1326
1327     hres = create_object(ctx->script, NULL, &obj);
1328     if(FAILED(hres))
1329         return hres;
1330
1331     var_set_jsdisp(&v, obj);
1332     return stack_push(ctx, &v);
1333 }
1334
1335 /* ECMA-262 3rd Edition    11.1.5 */
1336 static HRESULT interp_obj_prop(exec_ctx_t *ctx)
1337 {
1338     const BSTR name = get_op_bstr(ctx, 0);
1339     jsdisp_t *obj;
1340     VARIANT *v;
1341     jsval_t val;
1342     HRESULT hres;
1343
1344     TRACE("%s\n", debugstr_w(name));
1345
1346     v = stack_pop(ctx);
1347
1348     assert(V_VT(stack_top(ctx)) == VT_DISPATCH);
1349     obj = as_jsdisp(V_DISPATCH(stack_top(ctx)));
1350
1351     hres = variant_to_jsval(v, &val);
1352     if(SUCCEEDED(hres)) {
1353         hres = jsdisp_propput_name(obj, name, val, ctx->ei);
1354         jsval_release(val);
1355     }
1356     VariantClear(v);
1357     return hres;
1358 }
1359
1360 /* ECMA-262 3rd Edition    11.11 */
1361 static HRESULT interp_cnd_nz(exec_ctx_t *ctx)
1362 {
1363     const unsigned arg = get_op_uint(ctx, 0);
1364     VARIANT_BOOL b;
1365     HRESULT hres;
1366
1367     TRACE("\n");
1368
1369     hres = to_boolean(stack_top(ctx), &b);
1370     if(FAILED(hres))
1371         return hres;
1372
1373     if(b) {
1374         ctx->ip = arg;
1375     }else {
1376         stack_popn(ctx, 1);
1377         ctx->ip++;
1378     }
1379     return S_OK;
1380 }
1381
1382 /* ECMA-262 3rd Edition    11.11 */
1383 static HRESULT interp_cnd_z(exec_ctx_t *ctx)
1384 {
1385     const unsigned arg = get_op_uint(ctx, 0);
1386     VARIANT_BOOL b;
1387     HRESULT hres;
1388
1389     TRACE("\n");
1390
1391     hres = to_boolean(stack_top(ctx), &b);
1392     if(FAILED(hres))
1393         return hres;
1394
1395     if(b) {
1396         stack_popn(ctx, 1);
1397         ctx->ip++;
1398     }else {
1399         ctx->ip = arg;
1400     }
1401     return S_OK;
1402 }
1403
1404 /* ECMA-262 3rd Edition    11.10 */
1405 static HRESULT interp_or(exec_ctx_t *ctx)
1406 {
1407     INT l, r;
1408     HRESULT hres;
1409
1410     TRACE("\n");
1411
1412     hres = stack_pop_int(ctx, &r);
1413     if(FAILED(hres))
1414         return hres;
1415
1416     hres = stack_pop_int(ctx, &l);
1417     if(FAILED(hres))
1418         return hres;
1419
1420     return stack_push_int(ctx, l|r);
1421 }
1422
1423 /* ECMA-262 3rd Edition    11.10 */
1424 static HRESULT interp_xor(exec_ctx_t *ctx)
1425 {
1426     INT l, r;
1427     HRESULT hres;
1428
1429     TRACE("\n");
1430
1431     hres = stack_pop_int(ctx, &r);
1432     if(FAILED(hres))
1433         return hres;
1434
1435     hres = stack_pop_int(ctx, &l);
1436     if(FAILED(hres))
1437         return hres;
1438
1439     return stack_push_int(ctx, l^r);
1440 }
1441
1442 /* ECMA-262 3rd Edition    11.10 */
1443 static HRESULT interp_and(exec_ctx_t *ctx)
1444 {
1445     INT l, r;
1446     HRESULT hres;
1447
1448     TRACE("\n");
1449
1450     hres = stack_pop_int(ctx, &r);
1451     if(FAILED(hres))
1452         return hres;
1453
1454     hres = stack_pop_int(ctx, &l);
1455     if(FAILED(hres))
1456         return hres;
1457
1458     return stack_push_int(ctx, l&r);
1459 }
1460
1461 /* ECMA-262 3rd Edition    11.8.6 */
1462 static HRESULT interp_instanceof(exec_ctx_t *ctx)
1463 {
1464     jsdisp_t *obj, *iter, *tmp = NULL;
1465     jsval_t prot;
1466     VARIANT *v;
1467     BOOL ret = FALSE;
1468     HRESULT hres;
1469
1470     static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0};
1471
1472     v = stack_pop(ctx);
1473     if(V_VT(v) != VT_DISPATCH || !V_DISPATCH(v)) {
1474         VariantClear(v);
1475         return throw_type_error(ctx->script, ctx->ei, JS_E_FUNCTION_EXPECTED, NULL);
1476     }
1477
1478     obj = iface_to_jsdisp((IUnknown*)V_DISPATCH(v));
1479     IDispatch_Release(V_DISPATCH(v));
1480     if(!obj) {
1481         FIXME("non-jsdisp objects not supported\n");
1482         return E_FAIL;
1483     }
1484
1485     if(is_class(obj, JSCLASS_FUNCTION)) {
1486         hres = jsdisp_propget_name(obj, prototypeW, &prot, ctx->ei);
1487     }else {
1488         hres = throw_type_error(ctx->script, ctx->ei, JS_E_FUNCTION_EXPECTED, NULL);
1489     }
1490     jsdisp_release(obj);
1491     if(FAILED(hres))
1492         return hres;
1493
1494     v = stack_pop(ctx);
1495
1496     if(is_object_instance(prot)) {
1497         if(V_VT(v) == VT_DISPATCH)
1498             tmp = iface_to_jsdisp((IUnknown*)V_DISPATCH(v));
1499         for(iter = tmp; !ret && iter; iter = iter->prototype) {
1500             hres = disp_cmp(get_object(prot), to_disp(iter), &ret);
1501             if(FAILED(hres))
1502                 break;
1503         }
1504
1505         if(tmp)
1506             jsdisp_release(tmp);
1507     }else {
1508         FIXME("prototype is not an object\n");
1509         hres = E_FAIL;
1510     }
1511
1512     jsval_release(prot);
1513     VariantClear(v);
1514     if(FAILED(hres))
1515         return hres;
1516
1517     return stack_push_bool(ctx, ret);
1518 }
1519
1520 /* ECMA-262 3rd Edition    11.8.7 */
1521 static HRESULT interp_in(exec_ctx_t *ctx)
1522 {
1523     VARIANT *obj, *v;
1524     DISPID id = 0;
1525     BOOL ret;
1526     BSTR str;
1527     HRESULT hres;
1528
1529     TRACE("\n");
1530
1531     obj = stack_pop(ctx);
1532     v = stack_pop(ctx);
1533
1534     if(V_VT(obj) != VT_DISPATCH || !V_DISPATCH(obj)) {
1535         VariantClear(obj);
1536         VariantClear(v);
1537         return throw_type_error(ctx->script, ctx->ei, JS_E_OBJECT_EXPECTED, NULL);
1538     }
1539
1540     hres = to_string(ctx->script, v, ctx->ei, &str);
1541     VariantClear(v);
1542     if(FAILED(hres)) {
1543         IDispatch_Release(V_DISPATCH(obj));
1544         return hres;
1545     }
1546
1547     hres = disp_get_id(ctx->script, V_DISPATCH(obj), str, 0, &id);
1548     IDispatch_Release(V_DISPATCH(obj));
1549     SysFreeString(str);
1550     if(SUCCEEDED(hres))
1551         ret = TRUE;
1552     else if(hres == DISP_E_UNKNOWNNAME)
1553         ret = FALSE;
1554     else
1555         return hres;
1556
1557     return stack_push_bool(ctx, ret);
1558 }
1559
1560 /* ECMA-262 3rd Edition    11.6.1 */
1561 static HRESULT add_eval(script_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexcept_t *ei, VARIANT *retv)
1562 {
1563     VARIANT r, l;
1564     HRESULT hres;
1565
1566     hres = to_primitive(ctx, lval, ei, &l, NO_HINT);
1567     if(FAILED(hres))
1568         return hres;
1569
1570     hres = to_primitive(ctx, rval, ei, &r, NO_HINT);
1571     if(FAILED(hres)) {
1572         VariantClear(&l);
1573         return hres;
1574     }
1575
1576     if(V_VT(&l) == VT_BSTR || V_VT(&r) == VT_BSTR) {
1577         BSTR lstr = NULL, rstr = NULL;
1578
1579         if(V_VT(&l) == VT_BSTR)
1580             lstr = V_BSTR(&l);
1581         else
1582             hres = to_string(ctx, &l, ei, &lstr);
1583
1584         if(SUCCEEDED(hres)) {
1585             if(V_VT(&r) == VT_BSTR)
1586                 rstr = V_BSTR(&r);
1587             else
1588                 hres = to_string(ctx, &r, ei, &rstr);
1589         }
1590
1591         if(SUCCEEDED(hres)) {
1592             int len1, len2;
1593
1594             len1 = SysStringLen(lstr);
1595             len2 = SysStringLen(rstr);
1596
1597             V_VT(retv) = VT_BSTR;
1598             V_BSTR(retv) = SysAllocStringLen(NULL, len1+len2);
1599             if(len1)
1600                 memcpy(V_BSTR(retv), lstr, len1*sizeof(WCHAR));
1601             if(len2)
1602                 memcpy(V_BSTR(retv)+len1, rstr, len2*sizeof(WCHAR));
1603             V_BSTR(retv)[len1+len2] = 0;
1604         }
1605
1606         if(V_VT(&l) != VT_BSTR)
1607             SysFreeString(lstr);
1608         if(V_VT(&r) != VT_BSTR)
1609             SysFreeString(rstr);
1610     }else {
1611         double nl, nr;
1612
1613         hres = to_number(ctx, &l, ei, &nl);
1614         if(SUCCEEDED(hres)) {
1615             hres = to_number(ctx, &r, ei, &nr);
1616             if(SUCCEEDED(hres))
1617                 num_set_val(retv, nl + nr);
1618         }
1619     }
1620
1621     VariantClear(&r);
1622     VariantClear(&l);
1623     return hres;
1624 }
1625
1626 /* ECMA-262 3rd Edition    11.6.1 */
1627 static HRESULT interp_add(exec_ctx_t *ctx)
1628 {
1629     VARIANT *l, *r, ret;
1630     HRESULT hres;
1631
1632     r = stack_pop(ctx);
1633     l = stack_pop(ctx);
1634
1635     TRACE("%s + %s\n", debugstr_variant(l), debugstr_variant(r));
1636
1637     hres = add_eval(ctx->script, l, r, ctx->ei, &ret);
1638     VariantClear(l);
1639     VariantClear(r);
1640     if(FAILED(hres))
1641         return hres;
1642
1643     return stack_push(ctx, &ret);
1644 }
1645
1646 /* ECMA-262 3rd Edition    11.6.2 */
1647 static HRESULT interp_sub(exec_ctx_t *ctx)
1648 {
1649     double l, r;
1650     HRESULT hres;
1651
1652     TRACE("\n");
1653
1654     hres = stack_pop_number(ctx, &r);
1655     if(FAILED(hres))
1656         return hres;
1657
1658     hres = stack_pop_number(ctx, &l);
1659     if(FAILED(hres))
1660         return hres;
1661
1662     return stack_push_number(ctx, l-r);
1663 }
1664
1665 /* ECMA-262 3rd Edition    11.5.1 */
1666 static HRESULT interp_mul(exec_ctx_t *ctx)
1667 {
1668     double l, r;
1669     HRESULT hres;
1670
1671     TRACE("\n");
1672
1673     hres = stack_pop_number(ctx, &r);
1674     if(FAILED(hres))
1675         return hres;
1676
1677     hres = stack_pop_number(ctx, &l);
1678     if(FAILED(hres))
1679         return hres;
1680
1681     return stack_push_number(ctx, l*r);
1682 }
1683
1684 /* ECMA-262 3rd Edition    11.5.2 */
1685 static HRESULT interp_div(exec_ctx_t *ctx)
1686 {
1687     double l, r;
1688     HRESULT hres;
1689
1690     TRACE("\n");
1691
1692     hres = stack_pop_number(ctx, &r);
1693     if(FAILED(hres))
1694         return hres;
1695
1696     hres = stack_pop_number(ctx, &l);
1697     if(FAILED(hres))
1698         return hres;
1699
1700     return stack_push_number(ctx, l/r);
1701 }
1702
1703 /* ECMA-262 3rd Edition    11.5.3 */
1704 static HRESULT interp_mod(exec_ctx_t *ctx)
1705 {
1706     double l, r;
1707     HRESULT hres;
1708
1709     TRACE("\n");
1710
1711     hres = stack_pop_number(ctx, &r);
1712     if(FAILED(hres))
1713         return hres;
1714
1715     hres = stack_pop_number(ctx, &l);
1716     if(FAILED(hres))
1717         return hres;
1718
1719     return stack_push_number(ctx, fmod(l, r));
1720 }
1721
1722 /* ECMA-262 3rd Edition    11.4.2 */
1723 static HRESULT interp_delete(exec_ctx_t *ctx)
1724 {
1725     VARIANT *obj_var, *name_var;
1726     IDispatchEx *dispex;
1727     IDispatch *obj;
1728     BSTR name;
1729     BOOL ret;
1730     HRESULT hres;
1731
1732     TRACE("\n");
1733
1734     name_var = stack_pop(ctx);
1735     obj_var = stack_pop(ctx);
1736
1737     hres = to_object(ctx->script, obj_var, &obj);
1738     VariantClear(obj_var);
1739     if(FAILED(hres)) {
1740         VariantClear(name_var);
1741         return hres;
1742     }
1743
1744     hres = to_string(ctx->script, name_var, ctx->ei, &name);
1745     VariantClear(name_var);
1746     if(FAILED(hres)) {
1747         IDispatch_Release(obj);
1748         return hres;
1749     }
1750
1751     hres = IDispatch_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
1752     if(SUCCEEDED(hres)) {
1753         hres = IDispatchEx_DeleteMemberByName(dispex, name, make_grfdex(ctx->script, fdexNameCaseSensitive));
1754         ret = TRUE;
1755         IDispatchEx_Release(dispex);
1756     }else {
1757         hres = S_OK;
1758         ret = FALSE;
1759     }
1760
1761     IDispatch_Release(obj);
1762     SysFreeString(name);
1763     if(FAILED(hres))
1764         return hres;
1765
1766     return stack_push_bool(ctx, ret);
1767 }
1768
1769 /* ECMA-262 3rd Edition    11.4.2 */
1770 static HRESULT interp_delete_ident(exec_ctx_t *ctx)
1771 {
1772     const BSTR arg = get_op_bstr(ctx, 0);
1773     IDispatchEx *dispex;
1774     exprval_t exprval;
1775     BOOL ret = FALSE;
1776     HRESULT hres;
1777
1778     TRACE("%s\n", debugstr_w(arg));
1779
1780     hres = identifier_eval(ctx->script, arg, &exprval);
1781     if(FAILED(hres))
1782         return hres;
1783
1784     if(exprval.type != EXPRVAL_IDREF) {
1785         FIXME("Unsupported exprval\n");
1786         exprval_release(&exprval);
1787         return E_NOTIMPL;
1788     }
1789
1790     hres = IDispatch_QueryInterface(exprval.u.idref.disp, &IID_IDispatchEx, (void**)&dispex);
1791     IDispatch_Release(exprval.u.idref.disp);
1792     if(SUCCEEDED(hres)) {
1793         hres = IDispatchEx_DeleteMemberByDispID(dispex, exprval.u.idref.id);
1794         IDispatchEx_Release(dispex);
1795         if(FAILED(hres))
1796             return hres;
1797
1798         ret = TRUE;
1799     }
1800
1801     return stack_push_bool(ctx, ret);
1802 }
1803
1804 /* ECMA-262 3rd Edition    11.4.2 */
1805 static HRESULT interp_void(exec_ctx_t *ctx)
1806 {
1807     VARIANT v;
1808
1809     TRACE("\n");
1810
1811     stack_popn(ctx, 1);
1812
1813     V_VT(&v) = VT_EMPTY;
1814     return stack_push(ctx, &v);
1815 }
1816
1817 /* ECMA-262 3rd Edition    11.4.3 */
1818 static HRESULT typeof_string(VARIANT *v, const WCHAR **ret)
1819 {
1820     switch(V_VT(v)) {
1821     case VT_EMPTY:
1822         *ret = undefinedW;
1823         break;
1824     case VT_NULL:
1825         *ret = objectW;
1826         break;
1827     case VT_BOOL:
1828         *ret = booleanW;
1829         break;
1830     case VT_I4:
1831     case VT_R8:
1832         *ret = numberW;
1833         break;
1834     case VT_BSTR:
1835         *ret = stringW;
1836         break;
1837     case VT_DISPATCH: {
1838         jsdisp_t *dispex;
1839
1840         if(V_DISPATCH(v) && (dispex = iface_to_jsdisp((IUnknown*)V_DISPATCH(v)))) {
1841             *ret = is_class(dispex, JSCLASS_FUNCTION) ? functionW : objectW;
1842             jsdisp_release(dispex);
1843         }else {
1844             *ret = objectW;
1845         }
1846         break;
1847     }
1848     default:
1849         FIXME("unhandled vt %d\n", V_VT(v));
1850         return E_NOTIMPL;
1851     }
1852
1853     return S_OK;
1854 }
1855
1856 /* ECMA-262 3rd Edition    11.4.3 */
1857 static HRESULT interp_typeofid(exec_ctx_t *ctx)
1858 {
1859     const WCHAR *ret;
1860     IDispatch *obj;
1861     VARIANT v;
1862     DISPID id;
1863     HRESULT hres;
1864
1865     static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
1866
1867     TRACE("\n");
1868
1869     obj = stack_pop_objid(ctx, &id);
1870     if(!obj)
1871         return stack_push_string(ctx, undefinedW);
1872
1873     V_VT(&v) = VT_EMPTY;
1874     hres = disp_propget(ctx->script, obj, id, &v, ctx->ei);
1875     IDispatch_Release(obj);
1876     if(FAILED(hres))
1877         return stack_push_string(ctx, unknownW);
1878
1879     hres = typeof_string(&v, &ret);
1880     VariantClear(&v);
1881     if(FAILED(hres))
1882         return hres;
1883
1884     return stack_push_string(ctx, ret);
1885 }
1886
1887 /* ECMA-262 3rd Edition    11.4.3 */
1888 static HRESULT interp_typeofident(exec_ctx_t *ctx)
1889 {
1890     const BSTR arg = get_op_bstr(ctx, 0);
1891     exprval_t exprval;
1892     const WCHAR *ret;
1893     VARIANT v;
1894     HRESULT hres;
1895
1896     TRACE("%s\n", debugstr_w(arg));
1897
1898     hres = identifier_eval(ctx->script, arg, &exprval);
1899     if(FAILED(hres))
1900         return hres;
1901
1902     if(exprval.type == EXPRVAL_INVALID) {
1903         hres = stack_push_string(ctx, undefinedW);
1904         exprval_release(&exprval);
1905         return hres;
1906     }
1907
1908     hres = exprval_to_value(ctx->script, &exprval, ctx->ei, &v);
1909     exprval_release(&exprval);
1910     if(FAILED(hres))
1911         return hres;
1912
1913     hres = typeof_string(&v, &ret);
1914     VariantClear(&v);
1915     if(FAILED(hres))
1916         return hres;
1917
1918     return stack_push_string(ctx, ret);
1919 }
1920
1921 /* ECMA-262 3rd Edition    11.4.3 */
1922 static HRESULT interp_typeof(exec_ctx_t *ctx)
1923 {
1924     const WCHAR *ret;
1925     VARIANT *v;
1926     HRESULT hres;
1927
1928     TRACE("\n");
1929
1930     v = stack_pop(ctx);
1931     hres = typeof_string(v, &ret);
1932     VariantClear(v);
1933     if(FAILED(hres))
1934         return hres;
1935
1936     return stack_push_string(ctx, ret);
1937 }
1938
1939 /* ECMA-262 3rd Edition    11.4.7 */
1940 static HRESULT interp_minus(exec_ctx_t *ctx)
1941 {
1942     double n;
1943     HRESULT hres;
1944
1945     TRACE("\n");
1946
1947     hres = stack_pop_number(ctx, &n);
1948     if(FAILED(hres))
1949         return hres;
1950
1951     return stack_push_number(ctx, -n);
1952 }
1953
1954 /* ECMA-262 3rd Edition    11.4.6 */
1955 static HRESULT interp_tonum(exec_ctx_t *ctx)
1956 {
1957     VARIANT *v;
1958     double n;
1959     HRESULT hres;
1960
1961     TRACE("\n");
1962
1963     v = stack_pop(ctx);
1964     hres = to_number(ctx->script, v, ctx->ei, &n);
1965     VariantClear(v);
1966     if(FAILED(hres))
1967         return hres;
1968
1969     return stack_push_number(ctx, n);
1970 }
1971
1972 /* ECMA-262 3rd Edition    11.3.1 */
1973 static HRESULT interp_postinc(exec_ctx_t *ctx)
1974 {
1975     const int arg = get_op_int(ctx, 0);
1976     IDispatch *obj;
1977     DISPID id;
1978     VARIANT v;
1979     HRESULT hres;
1980
1981     TRACE("%d\n", arg);
1982
1983     obj = stack_pop_objid(ctx, &id);
1984     if(!obj)
1985         return throw_type_error(ctx->script, ctx->ei, JS_E_OBJECT_EXPECTED, NULL);
1986
1987     hres = disp_propget(ctx->script, obj, id, &v, ctx->ei);
1988     if(SUCCEEDED(hres)) {
1989         VARIANT inc;
1990         double n;
1991
1992         hres = to_number(ctx->script, &v, ctx->ei, &n);
1993         if(SUCCEEDED(hres)) {
1994             num_set_val(&inc, n+(double)arg);
1995             hres = disp_propput(ctx->script, obj, id, &inc, ctx->ei);
1996         }
1997         if(FAILED(hres))
1998             VariantClear(&v);
1999     }
2000     IDispatch_Release(obj);
2001     if(FAILED(hres))
2002         return hres;
2003
2004     return stack_push(ctx, &v);
2005 }
2006
2007 /* ECMA-262 3rd Edition    11.4.4, 11.4.5 */
2008 static HRESULT interp_preinc(exec_ctx_t *ctx)
2009 {
2010     const int arg = get_op_int(ctx, 0);
2011     IDispatch *obj;
2012     DISPID id;
2013     VARIANT v;
2014     HRESULT hres;
2015
2016     TRACE("%d\n", arg);
2017
2018     obj = stack_pop_objid(ctx, &id);
2019     if(!obj)
2020         return throw_type_error(ctx->script, ctx->ei, JS_E_OBJECT_EXPECTED, NULL);
2021
2022     hres = disp_propget(ctx->script, obj, id, &v, ctx->ei);
2023     if(SUCCEEDED(hres)) {
2024         double n;
2025
2026         hres = to_number(ctx->script, &v, ctx->ei, &n);
2027         VariantClear(&v);
2028         if(SUCCEEDED(hres)) {
2029             num_set_val(&v, n+(double)arg);
2030             hres = disp_propput(ctx->script, obj, id, &v, ctx->ei);
2031         }
2032     }
2033     IDispatch_Release(obj);
2034     if(FAILED(hres))
2035         return hres;
2036
2037     return stack_push(ctx, &v);
2038 }
2039
2040 /* ECMA-262 3rd Edition    11.9.3 */
2041 static HRESULT equal_values(script_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexcept_t *ei, BOOL *ret)
2042 {
2043     if(V_VT(lval) == V_VT(rval) || (is_num_vt(V_VT(lval)) && is_num_vt(V_VT(rval))))
2044        return equal2_values(lval, rval, ret);
2045
2046     /* FIXME: NULL disps should be handled in more general way */
2047     if(V_VT(lval) == VT_DISPATCH && !V_DISPATCH(lval)) {
2048         VARIANT v;
2049         V_VT(&v) = VT_NULL;
2050         return equal_values(ctx, &v, rval, ei, ret);
2051     }
2052
2053     if(V_VT(rval) == VT_DISPATCH && !V_DISPATCH(rval)) {
2054         VARIANT v;
2055         V_VT(&v) = VT_NULL;
2056         return equal_values(ctx, lval, &v, ei, ret);
2057     }
2058
2059     if((V_VT(lval) == VT_NULL && V_VT(rval) == VT_EMPTY) ||
2060        (V_VT(lval) == VT_EMPTY && V_VT(rval) == VT_NULL)) {
2061         *ret = TRUE;
2062         return S_OK;
2063     }
2064
2065     if(V_VT(lval) == VT_BSTR && is_num_vt(V_VT(rval))) {
2066         VARIANT v;
2067         double n;
2068         HRESULT hres;
2069
2070         hres = to_number(ctx, lval, ei, &n);
2071         if(FAILED(hres))
2072             return hres;
2073
2074         /* FIXME: optimize */
2075         num_set_val(&v, n);
2076
2077         return equal_values(ctx, &v, rval, ei, ret);
2078     }
2079
2080     if(V_VT(rval) == VT_BSTR && is_num_vt(V_VT(lval))) {
2081         VARIANT v;
2082         double n;
2083         HRESULT hres;
2084
2085         hres = to_number(ctx, rval, ei, &n);
2086         if(FAILED(hres))
2087             return hres;
2088
2089         /* FIXME: optimize */
2090         num_set_val(&v, n);
2091
2092         return equal_values(ctx, lval, &v, ei, ret);
2093     }
2094
2095     if(V_VT(rval) == VT_BOOL) {
2096         VARIANT v;
2097
2098         num_set_int(&v, V_BOOL(rval) ? 1 : 0);
2099         return equal_values(ctx, lval, &v, ei, ret);
2100     }
2101
2102     if(V_VT(lval) == VT_BOOL) {
2103         VARIANT v;
2104
2105         num_set_int(&v, V_BOOL(lval) ? 1 : 0);
2106         return equal_values(ctx, &v, rval, ei, ret);
2107     }
2108
2109
2110     if(V_VT(rval) == VT_DISPATCH && (V_VT(lval) == VT_BSTR || is_num_vt(V_VT(lval)))) {
2111         VARIANT v;
2112         HRESULT hres;
2113
2114         hres = to_primitive(ctx, rval, ei, &v, NO_HINT);
2115         if(FAILED(hres))
2116             return hres;
2117
2118         hres = equal_values(ctx, lval, &v, ei, ret);
2119
2120         VariantClear(&v);
2121         return hres;
2122     }
2123
2124
2125     if(V_VT(lval) == VT_DISPATCH && (V_VT(rval) == VT_BSTR || is_num_vt(V_VT(rval)))) {
2126         VARIANT v;
2127         HRESULT hres;
2128
2129         hres = to_primitive(ctx, lval, ei, &v, NO_HINT);
2130         if(FAILED(hres))
2131             return hres;
2132
2133         hres = equal_values(ctx, &v, rval, ei, ret);
2134
2135         VariantClear(&v);
2136         return hres;
2137     }
2138
2139
2140     *ret = FALSE;
2141     return S_OK;
2142 }
2143
2144 /* ECMA-262 3rd Edition    11.9.1 */
2145 static HRESULT interp_eq(exec_ctx_t *ctx)
2146 {
2147     VARIANT *l, *r;
2148     BOOL b;
2149     HRESULT hres;
2150
2151     r = stack_pop(ctx);
2152     l = stack_pop(ctx);
2153
2154     TRACE("%s == %s\n", debugstr_variant(l), debugstr_variant(r));
2155
2156     hres = equal_values(ctx->script, l, r, ctx->ei, &b);
2157     VariantClear(l);
2158     VariantClear(r);
2159     if(FAILED(hres))
2160         return hres;
2161
2162     return stack_push_bool(ctx, b);
2163 }
2164
2165 /* ECMA-262 3rd Edition    11.9.2 */
2166 static HRESULT interp_neq(exec_ctx_t *ctx)
2167 {
2168     VARIANT *l, *r;
2169     BOOL b;
2170     HRESULT hres;
2171
2172     r = stack_pop(ctx);
2173     l = stack_pop(ctx);
2174
2175     TRACE("%s != %s\n", debugstr_variant(l), debugstr_variant(r));
2176
2177     hres = equal_values(ctx->script, l, r, ctx->ei, &b);
2178     VariantClear(l);
2179     VariantClear(r);
2180     if(FAILED(hres))
2181         return hres;
2182
2183     return stack_push_bool(ctx, !b);
2184 }
2185
2186 /* ECMA-262 3rd Edition    11.9.4 */
2187 static HRESULT interp_eq2(exec_ctx_t *ctx)
2188 {
2189     VARIANT *l, *r;
2190     BOOL b;
2191     HRESULT hres;
2192
2193     TRACE("\n");
2194
2195     r = stack_pop(ctx);
2196     l = stack_pop(ctx);
2197
2198     hres = equal2_values(r, l, &b);
2199     VariantClear(l);
2200     VariantClear(r);
2201     if(FAILED(hres))
2202         return hres;
2203
2204     return stack_push_bool(ctx, b);
2205 }
2206
2207 /* ECMA-262 3rd Edition    11.9.5 */
2208 static HRESULT interp_neq2(exec_ctx_t *ctx)
2209 {
2210     VARIANT *l, *r;
2211     BOOL b;
2212     HRESULT hres;
2213
2214     TRACE("\n");
2215
2216     r = stack_pop(ctx);
2217     l = stack_pop(ctx);
2218
2219     hres = equal2_values(r, l, &b);
2220     VariantClear(l);
2221     VariantClear(r);
2222     if(FAILED(hres))
2223         return hres;
2224
2225     return stack_push_bool(ctx, !b);
2226 }
2227
2228 /* ECMA-262 3rd Edition    11.8.5 */
2229 static HRESULT less_eval(script_ctx_t *ctx, VARIANT *lval, VARIANT *rval, BOOL greater, jsexcept_t *ei, BOOL *ret)
2230 {
2231     double ln, rn;
2232     VARIANT l, r;
2233     HRESULT hres;
2234
2235     hres = to_primitive(ctx, lval, ei, &l, NO_HINT);
2236     if(FAILED(hres))
2237         return hres;
2238
2239     hres = to_primitive(ctx, rval, ei, &r, NO_HINT);
2240     if(FAILED(hres)) {
2241         VariantClear(&l);
2242         return hres;
2243     }
2244
2245     if(V_VT(&l) == VT_BSTR && V_VT(&r) == VT_BSTR) {
2246         *ret = (strcmpW(V_BSTR(&l), V_BSTR(&r)) < 0) ^ greater;
2247         SysFreeString(V_BSTR(&l));
2248         SysFreeString(V_BSTR(&r));
2249         return S_OK;
2250     }
2251
2252     hres = to_number(ctx, &l, ei, &ln);
2253     VariantClear(&l);
2254     if(SUCCEEDED(hres))
2255         hres = to_number(ctx, &r, ei, &rn);
2256     VariantClear(&r);
2257     if(FAILED(hres))
2258         return hres;
2259
2260     *ret = !isnan(ln) && !isnan(rn) && ((ln < rn) ^ greater);
2261     return S_OK;
2262 }
2263
2264 /* ECMA-262 3rd Edition    11.8.1 */
2265 static HRESULT interp_lt(exec_ctx_t *ctx)
2266 {
2267     VARIANT *l, *r;
2268     BOOL b;
2269     HRESULT hres;
2270
2271     r = stack_pop(ctx);
2272     l = stack_pop(ctx);
2273
2274     TRACE("%s < %s\n", debugstr_variant(l), debugstr_variant(r));
2275
2276     hres = less_eval(ctx->script, l, r, FALSE, ctx->ei, &b);
2277     VariantClear(l);
2278     VariantClear(r);
2279     if(FAILED(hres))
2280         return hres;
2281
2282     return stack_push_bool(ctx, b);
2283 }
2284
2285 /* ECMA-262 3rd Edition    11.8.1 */
2286 static HRESULT interp_lteq(exec_ctx_t *ctx)
2287 {
2288     VARIANT *l, *r;
2289     BOOL b;
2290     HRESULT hres;
2291
2292     r = stack_pop(ctx);
2293     l = stack_pop(ctx);
2294
2295     TRACE("%s <= %s\n", debugstr_variant(l), debugstr_variant(r));
2296
2297     hres = less_eval(ctx->script, r, l, TRUE, ctx->ei, &b);
2298     VariantClear(l);
2299     VariantClear(r);
2300     if(FAILED(hres))
2301         return hres;
2302
2303     return stack_push_bool(ctx, b);
2304 }
2305
2306 /* ECMA-262 3rd Edition    11.8.2 */
2307 static HRESULT interp_gt(exec_ctx_t *ctx)
2308 {
2309     VARIANT *l, *r;
2310     BOOL b;
2311     HRESULT hres;
2312
2313     r = stack_pop(ctx);
2314     l = stack_pop(ctx);
2315
2316     TRACE("%s > %s\n", debugstr_variant(l), debugstr_variant(r));
2317
2318     hres = less_eval(ctx->script, r, l, FALSE, ctx->ei, &b);
2319     VariantClear(l);
2320     VariantClear(r);
2321     if(FAILED(hres))
2322         return hres;
2323
2324     return stack_push_bool(ctx, b);
2325 }
2326
2327 /* ECMA-262 3rd Edition    11.8.4 */
2328 static HRESULT interp_gteq(exec_ctx_t *ctx)
2329 {
2330     VARIANT *l, *r;
2331     BOOL b;
2332     HRESULT hres;
2333
2334     r = stack_pop(ctx);
2335     l = stack_pop(ctx);
2336
2337     TRACE("%s >= %s\n", debugstr_variant(l), debugstr_variant(r));
2338
2339     hres = less_eval(ctx->script, l, r, TRUE, ctx->ei, &b);
2340     VariantClear(l);
2341     VariantClear(r);
2342     if(FAILED(hres))
2343         return hres;
2344
2345     return stack_push_bool(ctx, b);
2346 }
2347
2348 /* ECMA-262 3rd Edition    11.4.8 */
2349 static HRESULT interp_bneg(exec_ctx_t *ctx)
2350 {
2351     VARIANT *v;
2352     INT i;
2353     HRESULT hres;
2354
2355     TRACE("\n");
2356
2357     v = stack_pop(ctx);
2358     hres = to_int32_var(ctx->script, v, ctx->ei, &i);
2359     VariantClear(v);
2360     if(FAILED(hres))
2361         return hres;
2362
2363     return stack_push_int(ctx, ~i);
2364 }
2365
2366 /* ECMA-262 3rd Edition    11.4.9 */
2367 static HRESULT interp_neg(exec_ctx_t *ctx)
2368 {
2369     VARIANT *v;
2370     VARIANT_BOOL b;
2371     HRESULT hres;
2372
2373     TRACE("\n");
2374
2375     v = stack_pop(ctx);
2376     hres = to_boolean(v, &b);
2377     VariantClear(v);
2378     if(FAILED(hres))
2379         return hres;
2380
2381     return stack_push_bool(ctx, !b);
2382 }
2383
2384 /* ECMA-262 3rd Edition    11.7.1 */
2385 static HRESULT interp_lshift(exec_ctx_t *ctx)
2386 {
2387     DWORD r;
2388     INT l;
2389     HRESULT hres;
2390
2391     hres = stack_pop_uint(ctx, &r);
2392     if(FAILED(hres))
2393         return hres;
2394
2395     hres = stack_pop_int(ctx, &l);
2396     if(FAILED(hres))
2397         return hres;
2398
2399     return stack_push_int(ctx, l << (r&0x1f));
2400 }
2401
2402 /* ECMA-262 3rd Edition    11.7.2 */
2403 static HRESULT interp_rshift(exec_ctx_t *ctx)
2404 {
2405     DWORD r;
2406     INT l;
2407     HRESULT hres;
2408
2409     hres = stack_pop_uint(ctx, &r);
2410     if(FAILED(hres))
2411         return hres;
2412
2413     hres = stack_pop_int(ctx, &l);
2414     if(FAILED(hres))
2415         return hres;
2416
2417     return stack_push_int(ctx, l >> (r&0x1f));
2418 }
2419
2420 /* ECMA-262 3rd Edition    11.7.3 */
2421 static HRESULT interp_rshift2(exec_ctx_t *ctx)
2422 {
2423     DWORD r, l;
2424     HRESULT hres;
2425
2426     hres = stack_pop_uint(ctx, &r);
2427     if(FAILED(hres))
2428         return hres;
2429
2430     hres = stack_pop_uint(ctx, &l);
2431     if(FAILED(hres))
2432         return hres;
2433
2434     return stack_push_int(ctx, l >> (r&0x1f));
2435 }
2436
2437 /* ECMA-262 3rd Edition    11.13.1 */
2438 static HRESULT interp_assign(exec_ctx_t *ctx)
2439 {
2440     IDispatch *disp;
2441     DISPID id;
2442     VARIANT *v;
2443     HRESULT hres;
2444
2445     TRACE("\n");
2446
2447     v = stack_pop(ctx);
2448     disp = stack_pop_objid(ctx, &id);
2449
2450     if(!disp)
2451         return throw_reference_error(ctx->script, ctx->ei, JS_E_ILLEGAL_ASSIGN, NULL);
2452
2453     hres = disp_propput(ctx->script, disp, id, v, ctx->ei);
2454     IDispatch_Release(disp);
2455     if(FAILED(hres)) {
2456         VariantClear(v);
2457         return hres;
2458     }
2459
2460     return stack_push(ctx, v);
2461 }
2462
2463 /* JScript extension */
2464 static HRESULT interp_assign_call(exec_ctx_t *ctx)
2465 {
2466     const unsigned argc = get_op_uint(ctx, 0);
2467     IDispatch *disp;
2468     jsval_t *argv;
2469     unsigned i;
2470     VARIANT *v;
2471     DISPID id;
2472     HRESULT hres;
2473
2474     TRACE("%u\n", argc);
2475
2476     disp = stack_topn_objid(ctx, argc+1, &id);
2477     if(!disp)
2478         return throw_reference_error(ctx->script, ctx->ei, JS_E_ILLEGAL_ASSIGN, NULL);
2479
2480     hres = convert_args(ctx, argc+1, &argv);
2481     if(FAILED(hres))
2482         return hres;
2483
2484     hres = disp_call(ctx->script, disp, id, DISPATCH_PROPERTYPUT, argc+1, argv, NULL, ctx->ei);
2485     for(i=0; i < argc; i++)
2486         jsval_release(argv[i]);
2487     heap_free(argv);
2488     if(FAILED(hres))
2489         return hres;
2490
2491     v = stack_pop(ctx);
2492     stack_popn(ctx, argc+2);
2493     return stack_push(ctx, v);
2494 }
2495
2496 static HRESULT interp_undefined(exec_ctx_t *ctx)
2497 {
2498     VARIANT v;
2499
2500     TRACE("\n");
2501
2502     V_VT(&v) = VT_EMPTY;
2503     return stack_push(ctx, &v);
2504 }
2505
2506 static HRESULT interp_jmp(exec_ctx_t *ctx)
2507 {
2508     const unsigned arg = get_op_uint(ctx, 0);
2509
2510     TRACE("%u\n", arg);
2511
2512     ctx->ip = arg;
2513     return S_OK;
2514 }
2515
2516 static HRESULT interp_jmp_z(exec_ctx_t *ctx)
2517 {
2518     const unsigned arg = get_op_uint(ctx, 0);
2519     VARIANT_BOOL b;
2520     VARIANT *v;
2521     HRESULT hres;
2522
2523     TRACE("\n");
2524
2525     v = stack_pop(ctx);
2526     hres = to_boolean(v, &b);
2527     VariantClear(v);
2528     if(FAILED(hres))
2529         return hres;
2530
2531     if(b)
2532         ctx->ip++;
2533     else
2534         ctx->ip = arg;
2535     return S_OK;
2536 }
2537
2538 static HRESULT interp_pop(exec_ctx_t *ctx)
2539 {
2540     TRACE("\n");
2541
2542     stack_popn(ctx, 1);
2543     return S_OK;
2544 }
2545
2546 static HRESULT interp_ret(exec_ctx_t *ctx)
2547 {
2548     TRACE("\n");
2549
2550     ctx->ip = -1;
2551     return S_OK;
2552 }
2553
2554 typedef HRESULT (*op_func_t)(exec_ctx_t*);
2555
2556 static const op_func_t op_funcs[] = {
2557 #define X(x,a,b,c) interp_##x,
2558 OP_LIST
2559 #undef X
2560 };
2561
2562 static const unsigned op_move[] = {
2563 #define X(a,x,b,c) x,
2564 OP_LIST
2565 #undef X
2566 };
2567
2568 static HRESULT unwind_exception(exec_ctx_t *ctx)
2569 {
2570     except_frame_t *except_frame;
2571     VARIANT except_val;
2572     BSTR ident;
2573     HRESULT hres;
2574
2575     except_frame = ctx->except_frame;
2576     ctx->except_frame = except_frame->next;
2577
2578     assert(except_frame->stack_top <= ctx->top);
2579     stack_popn(ctx, ctx->top - except_frame->stack_top);
2580
2581     while(except_frame->scope != ctx->scope_chain)
2582         scope_pop(&ctx->scope_chain);
2583
2584     ctx->ip = except_frame->catch_off;
2585
2586     except_val = ctx->ei->var;
2587     memset(ctx->ei, 0, sizeof(*ctx->ei));
2588
2589     ident = except_frame->ident;
2590     heap_free(except_frame);
2591
2592     if(ident) {
2593         jsdisp_t *scope_obj;
2594
2595         hres = create_dispex(ctx->script, NULL, NULL, &scope_obj);
2596         if(SUCCEEDED(hres)) {
2597             jsval_t val;
2598
2599             hres = variant_to_jsval(&except_val, &val);
2600             if(SUCCEEDED(hres)) {
2601                 hres = jsdisp_propput_name(scope_obj, ident, val, ctx->ei);
2602                 jsval_release(val);
2603             }
2604             if(FAILED(hres))
2605                 jsdisp_release(scope_obj);
2606         }
2607         VariantClear(&except_val);
2608         if(FAILED(hres))
2609             return hres;
2610
2611         hres = scope_push(ctx->scope_chain, scope_obj, to_disp(scope_obj), &ctx->scope_chain);
2612         jsdisp_release(scope_obj);
2613     }else {
2614         VARIANT v;
2615
2616         hres = stack_push(ctx, &except_val);
2617         if(FAILED(hres))
2618             return hres;
2619
2620         hres = stack_push_bool(ctx, FALSE);
2621         if(FAILED(hres))
2622             return hres;
2623
2624         V_VT(&v) = VT_EMPTY;
2625         hres = stack_push(ctx, &v);
2626     }
2627
2628     return hres;
2629 }
2630
2631 static HRESULT enter_bytecode(script_ctx_t *ctx, bytecode_t *code, function_code_t *func, jsexcept_t *ei, VARIANT *ret)
2632 {
2633     exec_ctx_t *exec_ctx = ctx->exec_ctx;
2634     except_frame_t *prev_except_frame;
2635     function_code_t *prev_func;
2636     unsigned prev_ip, prev_top;
2637     scope_chain_t *prev_scope;
2638     bytecode_t *prev_code;
2639     jsexcept_t *prev_ei;
2640     jsop_t op;
2641     HRESULT hres = S_OK;
2642
2643     TRACE("\n");
2644
2645     prev_top = exec_ctx->top;
2646     prev_scope = exec_ctx->scope_chain;
2647     prev_except_frame = exec_ctx->except_frame;
2648     prev_ip = exec_ctx->ip;
2649     prev_ei = exec_ctx->ei;
2650     prev_code = exec_ctx->code;
2651     prev_func = exec_ctx->func_code;
2652     exec_ctx->ip = func->instr_off;
2653     exec_ctx->ei = ei;
2654     exec_ctx->except_frame = NULL;
2655     exec_ctx->code = code;
2656     exec_ctx->func_code = func;
2657
2658     while(exec_ctx->ip != -1) {
2659         op = code->instrs[exec_ctx->ip].op;
2660         TRACE("top %d\n", exec_ctx->top);
2661         hres = op_funcs[op](exec_ctx);
2662         if(FAILED(hres)) {
2663             TRACE("EXCEPTION\n");
2664
2665             if(!exec_ctx->except_frame)
2666                 break;
2667
2668             hres = unwind_exception(exec_ctx);
2669             if(FAILED(hres))
2670                 break;
2671         }else {
2672             exec_ctx->ip += op_move[op];
2673         }
2674     }
2675
2676     exec_ctx->ip = prev_ip;
2677     exec_ctx->ei = prev_ei;
2678     exec_ctx->except_frame = prev_except_frame;
2679     exec_ctx->code = prev_code;
2680     exec_ctx->func_code = prev_func;
2681
2682     if(FAILED(hres)) {
2683         while(exec_ctx->scope_chain != prev_scope)
2684             scope_pop(&exec_ctx->scope_chain);
2685         stack_popn(exec_ctx, exec_ctx->top-prev_top);
2686         return hres;
2687     }
2688
2689     assert(exec_ctx->top == prev_top+1 || exec_ctx->top == prev_top);
2690     assert(exec_ctx->scope_chain == prev_scope);
2691
2692     if(exec_ctx->top == prev_top)
2693         V_VT(ret) = VT_EMPTY;
2694     else
2695         *ret = *stack_pop(exec_ctx);
2696     return S_OK;
2697 }
2698
2699 HRESULT exec_source(exec_ctx_t *ctx, bytecode_t *code, function_code_t *func, BOOL from_eval,
2700         jsexcept_t *ei, VARIANT *retv)
2701 {
2702     exec_ctx_t *prev_ctx;
2703     VARIANT val;
2704     unsigned i;
2705     HRESULT hres = S_OK;
2706
2707     for(i = 0; i < func->func_cnt; i++) {
2708         jsdisp_t *func_obj;
2709
2710         if(!func->funcs[i].name)
2711             continue;
2712
2713         hres = create_source_function(ctx->script, code, func->funcs+i, ctx->scope_chain, &func_obj);
2714         if(FAILED(hres))
2715             return hres;
2716
2717         hres = jsdisp_propput_name(ctx->var_disp, func->funcs[i].name, jsval_obj(func_obj), ei);
2718         jsdisp_release(func_obj);
2719         if(FAILED(hres))
2720             return hres;
2721     }
2722
2723     for(i=0; i < func->var_cnt; i++) {
2724         if(!ctx->is_global || !lookup_global_members(ctx->script, func->variables[i], NULL)) {
2725             DISPID id = 0;
2726
2727             hres = jsdisp_get_id(ctx->var_disp, func->variables[i], fdexNameEnsure, &id);
2728             if(FAILED(hres))
2729                 return hres;
2730         }
2731     }
2732
2733     prev_ctx = ctx->script->exec_ctx;
2734     ctx->script->exec_ctx = ctx;
2735
2736     hres = enter_bytecode(ctx->script, code, func, ei, &val);
2737     assert(ctx->script->exec_ctx == ctx);
2738     ctx->script->exec_ctx = prev_ctx;
2739     if(FAILED(hres))
2740         return hres;
2741
2742     if(retv)
2743         *retv = val;
2744     else
2745         VariantClear(&val);
2746     return S_OK;
2747 }