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