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