mshtml: Use lazy allocation for connection points.
[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, 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, &name, 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
733     TRACE("%08x %s\n", hres, debugstr_jsstr(str));
734
735     return throw_type_error(ctx->script, hres, str->str);
736 }
737
738 /* ECMA-262 3rd Edition    12.14 */
739 static HRESULT interp_push_except(exec_ctx_t *ctx)
740 {
741     const unsigned arg1 = get_op_uint(ctx, 0);
742     const BSTR arg2 = get_op_bstr(ctx, 1);
743     except_frame_t *except;
744     unsigned stack_top;
745
746     TRACE("\n");
747
748     stack_top = ctx->top;
749
750     if(!arg2) {
751         HRESULT hres;
752
753         hres = stack_push(ctx, jsval_bool(TRUE));
754         if(FAILED(hres))
755             return hres;
756         hres = stack_push(ctx, jsval_bool(TRUE));
757         if(FAILED(hres))
758             return hres;
759     }
760
761     except = heap_alloc(sizeof(*except));
762     if(!except)
763         return E_OUTOFMEMORY;
764
765     except->stack_top = stack_top;
766     except->scope = ctx->scope_chain;
767     except->catch_off = arg1;
768     except->ident = arg2;
769     except->next = ctx->except_frame;
770     ctx->except_frame = except;
771     return S_OK;
772 }
773
774 /* ECMA-262 3rd Edition    12.14 */
775 static HRESULT interp_pop_except(exec_ctx_t *ctx)
776 {
777     except_frame_t *except;
778
779     TRACE("\n");
780
781     except = ctx->except_frame;
782     assert(except != NULL);
783
784     ctx->except_frame = except->next;
785     heap_free(except);
786     return S_OK;
787 }
788
789 /* ECMA-262 3rd Edition    12.14 */
790 static HRESULT interp_end_finally(exec_ctx_t *ctx)
791 {
792     jsval_t v;
793
794     TRACE("\n");
795
796     assert(is_bool(stack_top(ctx)));
797     if(!get_bool(stack_top(ctx))) {
798         TRACE("passing exception\n");
799
800         jsval_release(v);
801         stack_popn(ctx, 1);
802
803         ctx->script->ei.val = stack_pop(ctx);
804         return DISP_E_EXCEPTION;
805     }
806
807     stack_popn(ctx, 2);
808     return S_OK;
809 }
810
811 /* ECMA-262 3rd Edition    13 */
812 static HRESULT interp_func(exec_ctx_t *ctx)
813 {
814     unsigned func_idx = get_op_uint(ctx, 0);
815     jsdisp_t *dispex;
816     HRESULT hres;
817
818     TRACE("%d\n", func_idx);
819
820     hres = create_source_function(ctx->script, ctx->code, ctx->func_code->funcs+func_idx,
821             ctx->scope_chain, &dispex);
822     if(FAILED(hres))
823         return hres;
824
825     return stack_push(ctx, jsval_obj(dispex));
826 }
827
828 /* ECMA-262 3rd Edition    11.2.1 */
829 static HRESULT interp_array(exec_ctx_t *ctx)
830 {
831     jsval_t v, namev;
832     IDispatch *obj;
833     jsstr_t *name;
834     DISPID id;
835     HRESULT hres;
836
837     TRACE("\n");
838
839     namev = stack_pop(ctx);
840
841     hres = stack_pop_object(ctx, &obj);
842     if(FAILED(hres)) {
843         jsval_release(namev);
844         return hres;
845     }
846
847     hres = to_string(ctx->script, namev, &name);
848     jsval_release(namev);
849     if(FAILED(hres)) {
850         IDispatch_Release(obj);
851         return hres;
852     }
853
854     hres = disp_get_id(ctx->script, obj, name->str, NULL, 0, &id);
855     jsstr_release(name);
856     if(SUCCEEDED(hres)) {
857         hres = disp_propget(ctx->script, obj, id, &v);
858     }else if(hres == DISP_E_UNKNOWNNAME) {
859         v = jsval_undefined();
860         hres = S_OK;
861     }
862     IDispatch_Release(obj);
863     if(FAILED(hres))
864         return hres;
865
866     return stack_push(ctx, v);
867 }
868
869 /* ECMA-262 3rd Edition    11.2.1 */
870 static HRESULT interp_member(exec_ctx_t *ctx)
871 {
872     const BSTR arg = get_op_bstr(ctx, 0);
873     IDispatch *obj;
874     jsval_t v;
875     DISPID id;
876     HRESULT hres;
877
878     TRACE("\n");
879
880     hres = stack_pop_object(ctx, &obj);
881     if(FAILED(hres))
882         return hres;
883
884     hres = disp_get_id(ctx->script, obj, arg, arg, 0, &id);
885     if(SUCCEEDED(hres)) {
886         hres = disp_propget(ctx->script, obj, id, &v);
887     }else if(hres == DISP_E_UNKNOWNNAME) {
888         v = jsval_undefined();
889         hres = S_OK;
890     }
891     IDispatch_Release(obj);
892     if(FAILED(hres))
893         return hres;
894
895     return stack_push(ctx, v);
896 }
897
898 /* ECMA-262 3rd Edition    11.2.1 */
899 static HRESULT interp_memberid(exec_ctx_t *ctx)
900 {
901     const unsigned arg = get_op_uint(ctx, 0);
902     jsval_t objv, namev;
903     IDispatch *obj;
904     jsstr_t *name;
905     DISPID id;
906     HRESULT hres;
907
908     TRACE("%x\n", arg);
909
910     namev = stack_pop(ctx);
911     objv = stack_pop(ctx);
912
913     hres = to_object(ctx->script, objv, &obj);
914     jsval_release(objv);
915     if(SUCCEEDED(hres)) {
916         hres = to_string(ctx->script, namev, &name);
917         if(FAILED(hres))
918             IDispatch_Release(obj);
919     }
920     jsval_release(namev);
921     if(FAILED(hres))
922         return hres;
923
924     hres = disp_get_id(ctx->script, obj, name->str, NULL, arg, &id);
925     jsstr_release(name);
926     if(FAILED(hres)) {
927         IDispatch_Release(obj);
928         if(hres == DISP_E_UNKNOWNNAME && !(arg & fdexNameEnsure)) {
929             obj = NULL;
930             id = JS_E_INVALID_PROPERTY;
931         }else {
932             ERR("failed %08x\n", hres);
933             return hres;
934         }
935     }
936
937     return stack_push_objid(ctx, obj, id);
938 }
939
940 /* ECMA-262 3rd Edition    11.2.1 */
941 static HRESULT interp_refval(exec_ctx_t *ctx)
942 {
943     IDispatch *disp;
944     jsval_t v;
945     DISPID id;
946     HRESULT hres;
947
948     TRACE("\n");
949
950     disp = stack_topn_objid(ctx, 0, &id);
951     if(!disp)
952         return throw_reference_error(ctx->script, JS_E_ILLEGAL_ASSIGN, NULL);
953
954     hres = disp_propget(ctx->script, disp, id, &v);
955     if(FAILED(hres))
956         return hres;
957
958     return stack_push(ctx, v);
959 }
960
961 /* ECMA-262 3rd Edition    11.2.2 */
962 static HRESULT interp_new(exec_ctx_t *ctx)
963 {
964     const unsigned argc = get_op_uint(ctx, 0);
965     jsval_t r, constr;
966     HRESULT hres;
967
968     TRACE("%d\n", argc);
969
970     constr = stack_topn(ctx, argc);
971
972     /* NOTE: Should use to_object here */
973
974     if(is_null(constr))
975         return throw_type_error(ctx->script, JS_E_OBJECT_EXPECTED, NULL);
976     else if(!is_object_instance(constr))
977         return throw_type_error(ctx->script, JS_E_INVALID_ACTION, NULL);
978     else if(!get_object(constr))
979         return throw_type_error(ctx->script, JS_E_INVALID_PROPERTY, NULL);
980
981     hres = disp_call_value(ctx->script, get_object(constr), NULL, DISPATCH_CONSTRUCT, argc, stack_args(ctx, argc), &r);
982     if(FAILED(hres))
983         return hres;
984
985     stack_popn(ctx, argc+1);
986     return stack_push(ctx, r);
987 }
988
989 /* ECMA-262 3rd Edition    11.2.3 */
990 static HRESULT interp_call(exec_ctx_t *ctx)
991 {
992     const unsigned argn = get_op_uint(ctx, 0);
993     const int do_ret = get_op_int(ctx, 1);
994     jsval_t r, obj;
995     HRESULT hres;
996
997     TRACE("%d %d\n", argn, do_ret);
998
999     obj = stack_topn(ctx, argn);
1000     if(!is_object_instance(obj))
1001         return throw_type_error(ctx->script, JS_E_INVALID_PROPERTY, NULL);
1002
1003     hres = disp_call_value(ctx->script, get_object(obj), NULL, DISPATCH_METHOD, argn, stack_args(ctx, argn),
1004             do_ret ? &r : NULL);
1005     if(FAILED(hres))
1006         return hres;
1007
1008     stack_popn(ctx, argn+1);
1009     return do_ret ? stack_push(ctx, r) : S_OK;
1010 }
1011
1012 /* ECMA-262 3rd Edition    11.2.3 */
1013 static HRESULT interp_call_member(exec_ctx_t *ctx)
1014 {
1015     const unsigned argn = get_op_uint(ctx, 0);
1016     const int do_ret = get_op_int(ctx, 1);
1017     IDispatch *obj;
1018     jsval_t r;
1019     DISPID id;
1020     HRESULT hres;
1021
1022     TRACE("%d %d\n", argn, do_ret);
1023
1024     obj = stack_topn_objid(ctx, argn, &id);
1025     if(!obj)
1026         return throw_type_error(ctx->script, id, NULL);
1027
1028     hres = disp_call(ctx->script, obj, id, DISPATCH_METHOD, argn, stack_args(ctx, argn), do_ret ? &r : NULL);
1029     if(FAILED(hres))
1030         return hres;
1031
1032     stack_popn(ctx, argn+2);
1033     return do_ret ? stack_push(ctx, r) : S_OK;
1034
1035 }
1036
1037 /* ECMA-262 3rd Edition    11.1.1 */
1038 static HRESULT interp_this(exec_ctx_t *ctx)
1039 {
1040     TRACE("\n");
1041
1042     IDispatch_AddRef(ctx->this_obj);
1043     return stack_push(ctx, jsval_disp(ctx->this_obj));
1044 }
1045
1046 /* ECMA-262 3rd Edition    10.1.4 */
1047 static HRESULT interp_ident(exec_ctx_t *ctx)
1048 {
1049     const BSTR arg = get_op_bstr(ctx, 0);
1050     exprval_t exprval;
1051     jsval_t v;
1052     HRESULT hres;
1053
1054     TRACE("%s\n", debugstr_w(arg));
1055
1056     hres = identifier_eval(ctx->script, arg, &exprval);
1057     if(FAILED(hres))
1058         return hres;
1059
1060     if(exprval.type == EXPRVAL_INVALID)
1061         return throw_type_error(ctx->script, JS_E_UNDEFINED_VARIABLE, arg);
1062
1063     hres = exprval_to_value(ctx->script, &exprval, &v);
1064     exprval_release(&exprval);
1065     if(FAILED(hres))
1066         return hres;
1067
1068     return stack_push(ctx, v);
1069 }
1070
1071 /* ECMA-262 3rd Edition    10.1.4 */
1072 static HRESULT interp_identid(exec_ctx_t *ctx)
1073 {
1074     const BSTR arg = get_op_bstr(ctx, 0);
1075     const unsigned flags = get_op_uint(ctx, 1);
1076     exprval_t exprval;
1077     HRESULT hres;
1078
1079     TRACE("%s %x\n", debugstr_w(arg), flags);
1080
1081     hres = identifier_eval(ctx->script, arg, &exprval);
1082     if(FAILED(hres))
1083         return hres;
1084
1085     if(exprval.type == EXPRVAL_INVALID && (flags & fdexNameEnsure)) {
1086         DISPID id;
1087
1088         hres = jsdisp_get_id(ctx->script->global, arg, fdexNameEnsure, &id);
1089         if(FAILED(hres))
1090             return hres;
1091
1092         exprval_set_idref(&exprval, to_disp(ctx->script->global), id);
1093     }
1094
1095     if(exprval.type != EXPRVAL_IDREF) {
1096         WARN("invalid ref\n");
1097         exprval_release(&exprval);
1098         return stack_push_objid(ctx, NULL, JS_E_OBJECT_EXPECTED);
1099     }
1100
1101     return stack_push_objid(ctx, exprval.u.idref.disp, exprval.u.idref.id);
1102 }
1103
1104 /* ECMA-262 3rd Edition    7.8.1 */
1105 static HRESULT interp_null(exec_ctx_t *ctx)
1106 {
1107     TRACE("\n");
1108
1109     return stack_push(ctx, jsval_null());
1110 }
1111
1112 /* ECMA-262 3rd Edition    7.8.2 */
1113 static HRESULT interp_bool(exec_ctx_t *ctx)
1114 {
1115     const int arg = get_op_int(ctx, 0);
1116
1117     TRACE("%s\n", arg ? "true" : "false");
1118
1119     return stack_push(ctx, jsval_bool(arg));
1120 }
1121
1122 /* ECMA-262 3rd Edition    7.8.3 */
1123 static HRESULT interp_int(exec_ctx_t *ctx)
1124 {
1125     const int arg = get_op_int(ctx, 0);
1126
1127     TRACE("%d\n", arg);
1128
1129     return stack_push(ctx, jsval_number(arg));
1130 }
1131
1132 /* ECMA-262 3rd Edition    7.8.3 */
1133 static HRESULT interp_double(exec_ctx_t *ctx)
1134 {
1135     const double arg = get_op_double(ctx);
1136
1137     TRACE("%lf\n", arg);
1138
1139     return stack_push(ctx, jsval_number(arg));
1140 }
1141
1142 /* ECMA-262 3rd Edition    7.8.4 */
1143 static HRESULT interp_str(exec_ctx_t *ctx)
1144 {
1145     jsstr_t *str = get_op_str(ctx, 0);
1146
1147     TRACE("%s\n", debugstr_jsstr(str));
1148
1149     return stack_push(ctx, jsval_string(jsstr_addref(str)));
1150 }
1151
1152 /* ECMA-262 3rd Edition    7.8 */
1153 static HRESULT interp_regexp(exec_ctx_t *ctx)
1154 {
1155     jsstr_t *source = get_op_str(ctx, 0);
1156     const unsigned flags = get_op_uint(ctx, 1);
1157     jsdisp_t *regexp;
1158     HRESULT hres;
1159
1160     TRACE("%s %x\n", debugstr_jsstr(source), flags);
1161
1162     hres = create_regexp(ctx->script, source, flags, &regexp);
1163     if(FAILED(hres))
1164         return hres;
1165
1166     return stack_push(ctx, jsval_obj(regexp));
1167 }
1168
1169 /* ECMA-262 3rd Edition    11.1.4 */
1170 static HRESULT interp_carray(exec_ctx_t *ctx)
1171 {
1172     const unsigned arg = get_op_uint(ctx, 0);
1173     jsdisp_t *array;
1174     jsval_t val;
1175     unsigned i;
1176     HRESULT hres;
1177
1178     TRACE("%u\n", arg);
1179
1180     hres = create_array(ctx->script, arg, &array);
1181     if(FAILED(hres))
1182         return hres;
1183
1184     i = arg;
1185     while(i--) {
1186         val = stack_pop(ctx);
1187         hres = jsdisp_propput_idx(array, i, val);
1188         jsval_release(val);
1189         if(FAILED(hres)) {
1190             jsdisp_release(array);
1191             return hres;
1192         }
1193     }
1194
1195     return stack_push(ctx, jsval_obj(array));
1196 }
1197
1198 /* ECMA-262 3rd Edition    11.1.5 */
1199 static HRESULT interp_new_obj(exec_ctx_t *ctx)
1200 {
1201     jsdisp_t *obj;
1202     HRESULT hres;
1203
1204     TRACE("\n");
1205
1206     hres = create_object(ctx->script, NULL, &obj);
1207     if(FAILED(hres))
1208         return hres;
1209
1210     return stack_push(ctx, jsval_obj(obj));
1211 }
1212
1213 /* ECMA-262 3rd Edition    11.1.5 */
1214 static HRESULT interp_obj_prop(exec_ctx_t *ctx)
1215 {
1216     const BSTR name = get_op_bstr(ctx, 0);
1217     jsdisp_t *obj;
1218     jsval_t val;
1219     HRESULT hres;
1220
1221     TRACE("%s\n", debugstr_w(name));
1222
1223     val = stack_pop(ctx);
1224
1225     assert(is_object_instance(stack_top(ctx)));
1226     obj = as_jsdisp(get_object(stack_top(ctx)));
1227
1228     hres = jsdisp_propput_name(obj, name, val);
1229     jsval_release(val);
1230     return hres;
1231 }
1232
1233 /* ECMA-262 3rd Edition    11.11 */
1234 static HRESULT interp_cnd_nz(exec_ctx_t *ctx)
1235 {
1236     const unsigned arg = get_op_uint(ctx, 0);
1237     BOOL b;
1238     HRESULT hres;
1239
1240     TRACE("\n");
1241
1242     hres = to_boolean(stack_top(ctx), &b);
1243     if(FAILED(hres))
1244         return hres;
1245
1246     if(b) {
1247         ctx->ip = arg;
1248     }else {
1249         stack_popn(ctx, 1);
1250         ctx->ip++;
1251     }
1252     return S_OK;
1253 }
1254
1255 /* ECMA-262 3rd Edition    11.11 */
1256 static HRESULT interp_cnd_z(exec_ctx_t *ctx)
1257 {
1258     const unsigned arg = get_op_uint(ctx, 0);
1259     BOOL b;
1260     HRESULT hres;
1261
1262     TRACE("\n");
1263
1264     hres = to_boolean(stack_top(ctx), &b);
1265     if(FAILED(hres))
1266         return hres;
1267
1268     if(b) {
1269         stack_popn(ctx, 1);
1270         ctx->ip++;
1271     }else {
1272         ctx->ip = arg;
1273     }
1274     return S_OK;
1275 }
1276
1277 /* ECMA-262 3rd Edition    11.10 */
1278 static HRESULT interp_or(exec_ctx_t *ctx)
1279 {
1280     INT l, r;
1281     HRESULT hres;
1282
1283     TRACE("\n");
1284
1285     hres = stack_pop_int(ctx, &r);
1286     if(FAILED(hres))
1287         return hres;
1288
1289     hres = stack_pop_int(ctx, &l);
1290     if(FAILED(hres))
1291         return hres;
1292
1293     return stack_push(ctx, jsval_number(l|r));
1294 }
1295
1296 /* ECMA-262 3rd Edition    11.10 */
1297 static HRESULT interp_xor(exec_ctx_t *ctx)
1298 {
1299     INT l, r;
1300     HRESULT hres;
1301
1302     TRACE("\n");
1303
1304     hres = stack_pop_int(ctx, &r);
1305     if(FAILED(hres))
1306         return hres;
1307
1308     hres = stack_pop_int(ctx, &l);
1309     if(FAILED(hres))
1310         return hres;
1311
1312     return stack_push(ctx, jsval_number(l^r));
1313 }
1314
1315 /* ECMA-262 3rd Edition    11.10 */
1316 static HRESULT interp_and(exec_ctx_t *ctx)
1317 {
1318     INT l, r;
1319     HRESULT hres;
1320
1321     TRACE("\n");
1322
1323     hres = stack_pop_int(ctx, &r);
1324     if(FAILED(hres))
1325         return hres;
1326
1327     hres = stack_pop_int(ctx, &l);
1328     if(FAILED(hres))
1329         return hres;
1330
1331     return stack_push(ctx, jsval_number(l&r));
1332 }
1333
1334 /* ECMA-262 3rd Edition    11.8.6 */
1335 static HRESULT interp_instanceof(exec_ctx_t *ctx)
1336 {
1337     jsdisp_t *obj, *iter, *tmp = NULL;
1338     jsval_t prot, v;
1339     BOOL ret = FALSE;
1340     HRESULT hres;
1341
1342     static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0};
1343
1344     v = stack_pop(ctx);
1345     if(!is_object_instance(v) || !get_object(v)) {
1346         jsval_release(v);
1347         return throw_type_error(ctx->script, JS_E_FUNCTION_EXPECTED, NULL);
1348     }
1349
1350     obj = iface_to_jsdisp((IUnknown*)get_object(v));
1351     IDispatch_Release(get_object(v));
1352     if(!obj) {
1353         FIXME("non-jsdisp objects not supported\n");
1354         return E_FAIL;
1355     }
1356
1357     if(is_class(obj, JSCLASS_FUNCTION)) {
1358         hres = jsdisp_propget_name(obj, prototypeW, &prot);
1359     }else {
1360         hres = throw_type_error(ctx->script, JS_E_FUNCTION_EXPECTED, NULL);
1361     }
1362     jsdisp_release(obj);
1363     if(FAILED(hres))
1364         return hres;
1365
1366     v = stack_pop(ctx);
1367
1368     if(is_object_instance(prot)) {
1369         if(is_object_instance(v))
1370             tmp = iface_to_jsdisp((IUnknown*)get_object(v));
1371         for(iter = tmp; !ret && iter; iter = iter->prototype) {
1372             hres = disp_cmp(get_object(prot), to_disp(iter), &ret);
1373             if(FAILED(hres))
1374                 break;
1375         }
1376
1377         if(tmp)
1378             jsdisp_release(tmp);
1379     }else {
1380         FIXME("prototype is not an object\n");
1381         hres = E_FAIL;
1382     }
1383
1384     jsval_release(prot);
1385     jsval_release(v);
1386     if(FAILED(hres))
1387         return hres;
1388
1389     return stack_push(ctx, jsval_bool(ret));
1390 }
1391
1392 /* ECMA-262 3rd Edition    11.8.7 */
1393 static HRESULT interp_in(exec_ctx_t *ctx)
1394 {
1395     jsval_t obj, v;
1396     DISPID id = 0;
1397     BOOL ret;
1398     jsstr_t *str;
1399     HRESULT hres;
1400
1401     TRACE("\n");
1402
1403     obj = stack_pop(ctx);
1404     if(!is_object_instance(obj) || !get_object(obj)) {
1405         jsval_release(obj);
1406         return throw_type_error(ctx->script, JS_E_OBJECT_EXPECTED, NULL);
1407     }
1408
1409     v = stack_pop(ctx);
1410     hres = to_string(ctx->script, v, &str);
1411     jsval_release(v);
1412     if(FAILED(hres)) {
1413         IDispatch_Release(get_object(obj));
1414         return hres;
1415     }
1416
1417     hres = disp_get_id(ctx->script, get_object(obj), str->str, NULL, 0, &id);
1418     IDispatch_Release(get_object(obj));
1419     jsstr_release(str);
1420     if(SUCCEEDED(hres))
1421         ret = TRUE;
1422     else if(hres == DISP_E_UNKNOWNNAME)
1423         ret = FALSE;
1424     else
1425         return hres;
1426
1427     return stack_push(ctx, jsval_bool(ret));
1428 }
1429
1430 /* ECMA-262 3rd Edition    11.6.1 */
1431 static HRESULT add_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, jsval_t *ret)
1432 {
1433     jsval_t r, l;
1434     HRESULT hres;
1435
1436     hres = to_primitive(ctx, lval, &l, NO_HINT);
1437     if(FAILED(hres))
1438         return hres;
1439
1440     hres = to_primitive(ctx, rval, &r, NO_HINT);
1441     if(FAILED(hres)) {
1442         jsval_release(l);
1443         return hres;
1444     }
1445
1446     if(is_string(l) || is_string(r)) {
1447         jsstr_t *lstr, *rstr = NULL;
1448
1449         hres = to_string(ctx, l, &lstr);
1450         if(SUCCEEDED(hres))
1451             hres = to_string(ctx, r, &rstr);
1452
1453         if(SUCCEEDED(hres)) {
1454             jsstr_t *ret_str;
1455
1456             ret_str = jsstr_concat(lstr, rstr);
1457             if(ret_str)
1458                 *ret = jsval_string(ret_str);
1459             else
1460                 hres = E_OUTOFMEMORY;
1461         }
1462
1463         jsstr_release(lstr);
1464         if(rstr)
1465             jsstr_release(rstr);
1466     }else {
1467         double nl, nr;
1468
1469         hres = to_number(ctx, l, &nl);
1470         if(SUCCEEDED(hres)) {
1471             hres = to_number(ctx, r, &nr);
1472             if(SUCCEEDED(hres))
1473                 *ret = jsval_number(nl+nr);
1474         }
1475     }
1476
1477     jsval_release(r);
1478     jsval_release(l);
1479     return hres;
1480 }
1481
1482 /* ECMA-262 3rd Edition    11.6.1 */
1483 static HRESULT interp_add(exec_ctx_t *ctx)
1484 {
1485     jsval_t l, r, ret;
1486     HRESULT hres;
1487
1488     r = stack_pop(ctx);
1489     l = stack_pop(ctx);
1490
1491     TRACE("%s + %s\n", debugstr_jsval(l), debugstr_jsval(r));
1492
1493     hres = add_eval(ctx->script, l, r, &ret);
1494     jsval_release(l);
1495     jsval_release(r);
1496     if(FAILED(hres))
1497         return hres;
1498
1499     return stack_push(ctx, ret);
1500 }
1501
1502 /* ECMA-262 3rd Edition    11.6.2 */
1503 static HRESULT interp_sub(exec_ctx_t *ctx)
1504 {
1505     double l, r;
1506     HRESULT hres;
1507
1508     TRACE("\n");
1509
1510     hres = stack_pop_number(ctx, &r);
1511     if(FAILED(hres))
1512         return hres;
1513
1514     hres = stack_pop_number(ctx, &l);
1515     if(FAILED(hres))
1516         return hres;
1517
1518     return stack_push(ctx, jsval_number(l-r));
1519 }
1520
1521 /* ECMA-262 3rd Edition    11.5.1 */
1522 static HRESULT interp_mul(exec_ctx_t *ctx)
1523 {
1524     double l, r;
1525     HRESULT hres;
1526
1527     TRACE("\n");
1528
1529     hres = stack_pop_number(ctx, &r);
1530     if(FAILED(hres))
1531         return hres;
1532
1533     hres = stack_pop_number(ctx, &l);
1534     if(FAILED(hres))
1535         return hres;
1536
1537     return stack_push(ctx, jsval_number(l*r));
1538 }
1539
1540 /* ECMA-262 3rd Edition    11.5.2 */
1541 static HRESULT interp_div(exec_ctx_t *ctx)
1542 {
1543     double l, r;
1544     HRESULT hres;
1545
1546     TRACE("\n");
1547
1548     hres = stack_pop_number(ctx, &r);
1549     if(FAILED(hres))
1550         return hres;
1551
1552     hres = stack_pop_number(ctx, &l);
1553     if(FAILED(hres))
1554         return hres;
1555
1556     return stack_push(ctx, jsval_number(l/r));
1557 }
1558
1559 /* ECMA-262 3rd Edition    11.5.3 */
1560 static HRESULT interp_mod(exec_ctx_t *ctx)
1561 {
1562     double l, r;
1563     HRESULT hres;
1564
1565     TRACE("\n");
1566
1567     hres = stack_pop_number(ctx, &r);
1568     if(FAILED(hres))
1569         return hres;
1570
1571     hres = stack_pop_number(ctx, &l);
1572     if(FAILED(hres))
1573         return hres;
1574
1575     return stack_push(ctx, jsval_number(fmod(l, r)));
1576 }
1577
1578 /* ECMA-262 3rd Edition    11.4.2 */
1579 static HRESULT interp_delete(exec_ctx_t *ctx)
1580 {
1581     jsval_t objv, namev;
1582     IDispatch *obj;
1583     jsstr_t *name;
1584     BOOL ret;
1585     HRESULT hres;
1586
1587     TRACE("\n");
1588
1589     namev = stack_pop(ctx);
1590     objv = stack_pop(ctx);
1591
1592     hres = to_object(ctx->script, objv, &obj);
1593     jsval_release(objv);
1594     if(FAILED(hres)) {
1595         jsval_release(namev);
1596         return hres;
1597     }
1598
1599     hres = to_string(ctx->script, namev, &name);
1600     jsval_release(namev);
1601     if(FAILED(hres)) {
1602         IDispatch_Release(obj);
1603         return hres;
1604     }
1605
1606     hres = disp_delete_name(ctx->script, obj, name, &ret);
1607     IDispatch_Release(obj);
1608     jsstr_release(name);
1609     if(FAILED(hres))
1610         return hres;
1611
1612     return stack_push(ctx, jsval_bool(ret));
1613 }
1614
1615 /* ECMA-262 3rd Edition    11.4.2 */
1616 static HRESULT interp_delete_ident(exec_ctx_t *ctx)
1617 {
1618     const BSTR arg = get_op_bstr(ctx, 0);
1619     exprval_t exprval;
1620     BOOL ret;
1621     HRESULT hres;
1622
1623     TRACE("%s\n", debugstr_w(arg));
1624
1625     hres = identifier_eval(ctx->script, arg, &exprval);
1626     if(FAILED(hres))
1627         return hres;
1628
1629     switch(exprval.type) {
1630     case EXPRVAL_IDREF:
1631         hres = disp_delete(exprval.u.idref.disp, exprval.u.idref.id, &ret);
1632         IDispatch_Release(exprval.u.idref.disp);
1633         if(FAILED(hres))
1634             return ret;
1635         break;
1636     case EXPRVAL_INVALID:
1637         ret = TRUE;
1638         break;
1639     default:
1640         FIXME("Unsupported exprval\n");
1641         exprval_release(&exprval);
1642         return E_NOTIMPL;
1643     }
1644
1645
1646     return stack_push(ctx, jsval_bool(ret));
1647 }
1648
1649 /* ECMA-262 3rd Edition    11.4.2 */
1650 static HRESULT interp_void(exec_ctx_t *ctx)
1651 {
1652     TRACE("\n");
1653
1654     stack_popn(ctx, 1);
1655     return stack_push(ctx, jsval_undefined());
1656 }
1657
1658 /* ECMA-262 3rd Edition    11.4.3 */
1659 static HRESULT typeof_string(jsval_t v, const WCHAR **ret)
1660 {
1661     switch(jsval_type(v)) {
1662     case JSV_UNDEFINED:
1663         *ret = undefinedW;
1664         break;
1665     case JSV_NULL:
1666         *ret = objectW;
1667         break;
1668     case JSV_OBJECT: {
1669         jsdisp_t *dispex;
1670
1671         if(get_object(v) && (dispex = iface_to_jsdisp((IUnknown*)get_object(v)))) {
1672             *ret = is_class(dispex, JSCLASS_FUNCTION) ? functionW : objectW;
1673             jsdisp_release(dispex);
1674         }else {
1675             *ret = objectW;
1676         }
1677         break;
1678     }
1679     case JSV_STRING:
1680         *ret = stringW;
1681         break;
1682     case JSV_NUMBER:
1683         *ret = numberW;
1684         break;
1685     case JSV_BOOL:
1686         *ret = booleanW;
1687         break;
1688     case JSV_VARIANT:
1689         FIXME("unhandled variant %s\n", debugstr_variant(get_variant(v)));
1690         return E_NOTIMPL;
1691     }
1692
1693     return S_OK;
1694 }
1695
1696 /* ECMA-262 3rd Edition    11.4.3 */
1697 static HRESULT interp_typeofid(exec_ctx_t *ctx)
1698 {
1699     const WCHAR *ret;
1700     IDispatch *obj;
1701     jsval_t v;
1702     DISPID id;
1703     HRESULT hres;
1704
1705     TRACE("\n");
1706
1707     obj = stack_pop_objid(ctx, &id);
1708     if(!obj)
1709         return stack_push(ctx, jsval_string(jsstr_undefined()));
1710
1711     hres = disp_propget(ctx->script, obj, id, &v);
1712     IDispatch_Release(obj);
1713     if(FAILED(hres))
1714         return stack_push_string(ctx, unknownW);
1715
1716     hres = typeof_string(v, &ret);
1717     jsval_release(v);
1718     if(FAILED(hres))
1719         return hres;
1720
1721     return stack_push_string(ctx, ret);
1722 }
1723
1724 /* ECMA-262 3rd Edition    11.4.3 */
1725 static HRESULT interp_typeofident(exec_ctx_t *ctx)
1726 {
1727     const BSTR arg = get_op_bstr(ctx, 0);
1728     exprval_t exprval;
1729     const WCHAR *ret;
1730     jsval_t v;
1731     HRESULT hres;
1732
1733     TRACE("%s\n", debugstr_w(arg));
1734
1735     hres = identifier_eval(ctx->script, arg, &exprval);
1736     if(FAILED(hres))
1737         return hres;
1738
1739     if(exprval.type == EXPRVAL_INVALID) {
1740         hres = stack_push(ctx, jsval_string(jsstr_undefined()));
1741         exprval_release(&exprval);
1742         return hres;
1743     }
1744
1745     hres = exprval_to_value(ctx->script, &exprval, &v);
1746     exprval_release(&exprval);
1747     if(FAILED(hres))
1748         return hres;
1749
1750     hres = typeof_string(v, &ret);
1751     jsval_release(v);
1752     if(FAILED(hres))
1753         return hres;
1754
1755     return stack_push_string(ctx, ret);
1756 }
1757
1758 /* ECMA-262 3rd Edition    11.4.3 */
1759 static HRESULT interp_typeof(exec_ctx_t *ctx)
1760 {
1761     const WCHAR *ret;
1762     jsval_t v;
1763     HRESULT hres;
1764
1765     TRACE("\n");
1766
1767     v = stack_pop(ctx);
1768     hres = typeof_string(v, &ret);
1769     jsval_release(v);
1770     if(FAILED(hres))
1771         return hres;
1772
1773     return stack_push_string(ctx, ret);
1774 }
1775
1776 /* ECMA-262 3rd Edition    11.4.7 */
1777 static HRESULT interp_minus(exec_ctx_t *ctx)
1778 {
1779     double n;
1780     HRESULT hres;
1781
1782     TRACE("\n");
1783
1784     hres = stack_pop_number(ctx, &n);
1785     if(FAILED(hres))
1786         return hres;
1787
1788     return stack_push(ctx, jsval_number(-n));
1789 }
1790
1791 /* ECMA-262 3rd Edition    11.4.6 */
1792 static HRESULT interp_tonum(exec_ctx_t *ctx)
1793 {
1794     jsval_t v;
1795     double n;
1796     HRESULT hres;
1797
1798     TRACE("\n");
1799
1800     v = stack_pop(ctx);
1801     hres = to_number(ctx->script, v, &n);
1802     jsval_release(v);
1803     if(FAILED(hres))
1804         return hres;
1805
1806     return stack_push(ctx, jsval_number(n));
1807 }
1808
1809 /* ECMA-262 3rd Edition    11.3.1 */
1810 static HRESULT interp_postinc(exec_ctx_t *ctx)
1811 {
1812     const int arg = get_op_int(ctx, 0);
1813     IDispatch *obj;
1814     DISPID id;
1815     jsval_t v;
1816     HRESULT hres;
1817
1818     TRACE("%d\n", arg);
1819
1820     obj = stack_pop_objid(ctx, &id);
1821     if(!obj)
1822         return throw_type_error(ctx->script, JS_E_OBJECT_EXPECTED, NULL);
1823
1824     hres = disp_propget(ctx->script, obj, id, &v);
1825     if(SUCCEEDED(hres)) {
1826         double n;
1827
1828         hres = to_number(ctx->script, v, &n);
1829         if(SUCCEEDED(hres))
1830             hres = disp_propput(ctx->script, obj, id, jsval_number(n+(double)arg));
1831         if(FAILED(hres))
1832             jsval_release(v);
1833     }
1834     IDispatch_Release(obj);
1835     if(FAILED(hres))
1836         return hres;
1837
1838     return stack_push(ctx, v);
1839 }
1840
1841 /* ECMA-262 3rd Edition    11.4.4, 11.4.5 */
1842 static HRESULT interp_preinc(exec_ctx_t *ctx)
1843 {
1844     const int arg = get_op_int(ctx, 0);
1845     IDispatch *obj;
1846     double ret;
1847     DISPID id;
1848     jsval_t v;
1849     HRESULT hres;
1850
1851     TRACE("%d\n", arg);
1852
1853     obj = stack_pop_objid(ctx, &id);
1854     if(!obj)
1855         return throw_type_error(ctx->script, JS_E_OBJECT_EXPECTED, NULL);
1856
1857     hres = disp_propget(ctx->script, obj, id, &v);
1858     if(SUCCEEDED(hres)) {
1859         double n;
1860
1861         hres = to_number(ctx->script, v, &n);
1862         jsval_release(v);
1863         if(SUCCEEDED(hres)) {
1864             ret = n+(double)arg;
1865             hres = disp_propput(ctx->script, obj, id, jsval_number(ret));
1866         }
1867     }
1868     IDispatch_Release(obj);
1869     if(FAILED(hres))
1870         return hres;
1871
1872     return stack_push(ctx, jsval_number(ret));
1873 }
1874
1875 /* ECMA-262 3rd Edition    11.9.3 */
1876 static HRESULT equal_values(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL *ret)
1877 {
1878     if(jsval_type(lval) == jsval_type(rval) || (is_number(lval) && is_number(rval)))
1879        return equal2_values(lval, rval, ret);
1880
1881     /* FIXME: NULL disps should be handled in more general way */
1882     if(is_object_instance(lval) && !get_object(lval))
1883         return equal_values(ctx, jsval_null(), rval, ret);
1884     if(is_object_instance(rval) && !get_object(rval))
1885         return equal_values(ctx, lval, jsval_null(), ret);
1886
1887     if((is_null(lval) && is_undefined(rval)) || (is_undefined(lval) && is_null(rval))) {
1888         *ret = TRUE;
1889         return S_OK;
1890     }
1891
1892     if(is_string(lval) && is_number(rval)) {
1893         double n;
1894         HRESULT hres;
1895
1896         hres = to_number(ctx, lval, &n);
1897         if(FAILED(hres))
1898             return hres;
1899
1900         /* FIXME: optimize */
1901         return equal_values(ctx, jsval_number(n), rval, ret);
1902     }
1903
1904     if(is_string(rval) && is_number(lval)) {
1905         double n;
1906         HRESULT hres;
1907
1908         hres = to_number(ctx, rval, &n);
1909         if(FAILED(hres))
1910             return hres;
1911
1912         /* FIXME: optimize */
1913         return equal_values(ctx, lval, jsval_number(n), ret);
1914     }
1915
1916     if(is_bool(rval))
1917         return equal_values(ctx, lval, jsval_number(get_bool(rval) ? 1 : 0), ret);
1918
1919     if(is_bool(lval))
1920         return equal_values(ctx, jsval_number(get_bool(lval) ? 1 : 0), rval, ret);
1921
1922
1923     if(is_object_instance(rval) && (is_string(lval) || is_number(lval))) {
1924         jsval_t prim;
1925         HRESULT hres;
1926
1927         hres = to_primitive(ctx, rval, &prim, NO_HINT);
1928         if(FAILED(hres))
1929             return hres;
1930
1931         hres = equal_values(ctx, lval, prim, ret);
1932         jsval_release(prim);
1933         return hres;
1934     }
1935
1936
1937     if(is_object_instance(lval) && (is_string(rval) || is_number(rval))) {
1938         jsval_t prim;
1939         HRESULT hres;
1940
1941         hres = to_primitive(ctx, lval, &prim, NO_HINT);
1942         if(FAILED(hres))
1943             return hres;
1944
1945         hres = equal_values(ctx, prim, rval, ret);
1946         jsval_release(prim);
1947         return hres;
1948     }
1949
1950
1951     *ret = FALSE;
1952     return S_OK;
1953 }
1954
1955 /* ECMA-262 3rd Edition    11.9.1 */
1956 static HRESULT interp_eq(exec_ctx_t *ctx)
1957 {
1958     jsval_t l, r;
1959     BOOL b;
1960     HRESULT hres;
1961
1962     r = stack_pop(ctx);
1963     l = stack_pop(ctx);
1964
1965     TRACE("%s == %s\n", debugstr_jsval(l), debugstr_jsval(r));
1966
1967     hres = equal_values(ctx->script, l, r, &b);
1968     jsval_release(l);
1969     jsval_release(r);
1970     if(FAILED(hres))
1971         return hres;
1972
1973     return stack_push(ctx, jsval_bool(b));
1974 }
1975
1976 /* ECMA-262 3rd Edition    11.9.2 */
1977 static HRESULT interp_neq(exec_ctx_t *ctx)
1978 {
1979     jsval_t l, r;
1980     BOOL b;
1981     HRESULT hres;
1982
1983     r = stack_pop(ctx);
1984     l = stack_pop(ctx);
1985
1986     TRACE("%s != %s\n", debugstr_jsval(l), debugstr_jsval(r));
1987
1988     hres = equal_values(ctx->script, l, r, &b);
1989     jsval_release(l);
1990     jsval_release(r);
1991     if(FAILED(hres))
1992         return hres;
1993
1994     return stack_push(ctx, jsval_bool(!b));
1995 }
1996
1997 /* ECMA-262 3rd Edition    11.9.4 */
1998 static HRESULT interp_eq2(exec_ctx_t *ctx)
1999 {
2000     jsval_t l, r;
2001     BOOL b;
2002     HRESULT hres;
2003
2004     TRACE("\n");
2005
2006     r = stack_pop(ctx);
2007     l = stack_pop(ctx);
2008
2009     hres = equal2_values(r, l, &b);
2010     jsval_release(l);
2011     jsval_release(r);
2012     if(FAILED(hres))
2013         return hres;
2014
2015     return stack_push(ctx, jsval_bool(b));
2016 }
2017
2018 /* ECMA-262 3rd Edition    11.9.5 */
2019 static HRESULT interp_neq2(exec_ctx_t *ctx)
2020 {
2021     jsval_t l, r;
2022     BOOL b;
2023     HRESULT hres;
2024
2025     TRACE("\n");
2026
2027     r = stack_pop(ctx);
2028     l = stack_pop(ctx);
2029
2030     hres = equal2_values(r, l, &b);
2031     jsval_release(l);
2032     jsval_release(r);
2033     if(FAILED(hres))
2034         return hres;
2035
2036     return stack_push(ctx, jsval_bool(!b));
2037 }
2038
2039 /* ECMA-262 3rd Edition    11.8.5 */
2040 static HRESULT less_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL greater, BOOL *ret)
2041 {
2042     double ln, rn;
2043     jsval_t l, r;
2044     HRESULT hres;
2045
2046     hres = to_primitive(ctx, lval, &l, NO_HINT);
2047     if(FAILED(hres))
2048         return hres;
2049
2050     hres = to_primitive(ctx, rval, &r, NO_HINT);
2051     if(FAILED(hres)) {
2052         jsval_release(l);
2053         return hres;
2054     }
2055
2056     if(is_string(l) && is_string(r)) {
2057         *ret = (jsstr_cmp(get_string(l), get_string(r)) < 0) ^ greater;
2058         jsstr_release(get_string(l));
2059         jsstr_release(get_string(r));
2060         return S_OK;
2061     }
2062
2063     hres = to_number(ctx, l, &ln);
2064     jsval_release(l);
2065     if(SUCCEEDED(hres))
2066         hres = to_number(ctx, r, &rn);
2067     jsval_release(r);
2068     if(FAILED(hres))
2069         return hres;
2070
2071     *ret = !isnan(ln) && !isnan(rn) && ((ln < rn) ^ greater);
2072     return S_OK;
2073 }
2074
2075 /* ECMA-262 3rd Edition    11.8.1 */
2076 static HRESULT interp_lt(exec_ctx_t *ctx)
2077 {
2078     jsval_t l, r;
2079     BOOL b;
2080     HRESULT hres;
2081
2082     r = stack_pop(ctx);
2083     l = stack_pop(ctx);
2084
2085     TRACE("%s < %s\n", debugstr_jsval(l), debugstr_jsval(r));
2086
2087     hres = less_eval(ctx->script, l, r, FALSE, &b);
2088     jsval_release(l);
2089     jsval_release(r);
2090     if(FAILED(hres))
2091         return hres;
2092
2093     return stack_push(ctx, jsval_bool(b));
2094 }
2095
2096 /* ECMA-262 3rd Edition    11.8.1 */
2097 static HRESULT interp_lteq(exec_ctx_t *ctx)
2098 {
2099     jsval_t l, r;
2100     BOOL b;
2101     HRESULT hres;
2102
2103     r = stack_pop(ctx);
2104     l = stack_pop(ctx);
2105
2106     TRACE("%s <= %s\n", debugstr_jsval(l), debugstr_jsval(r));
2107
2108     hres = less_eval(ctx->script, r, l, TRUE, &b);
2109     jsval_release(l);
2110     jsval_release(r);
2111     if(FAILED(hres))
2112         return hres;
2113
2114     return stack_push(ctx, jsval_bool(b));
2115 }
2116
2117 /* ECMA-262 3rd Edition    11.8.2 */
2118 static HRESULT interp_gt(exec_ctx_t *ctx)
2119 {
2120     jsval_t l, r;
2121     BOOL b;
2122     HRESULT hres;
2123
2124     r = stack_pop(ctx);
2125     l = stack_pop(ctx);
2126
2127     TRACE("%s > %s\n", debugstr_jsval(l), debugstr_jsval(r));
2128
2129     hres = less_eval(ctx->script, r, l, FALSE, &b);
2130     jsval_release(l);
2131     jsval_release(r);
2132     if(FAILED(hres))
2133         return hres;
2134
2135     return stack_push(ctx, jsval_bool(b));
2136 }
2137
2138 /* ECMA-262 3rd Edition    11.8.4 */
2139 static HRESULT interp_gteq(exec_ctx_t *ctx)
2140 {
2141     jsval_t l, r;
2142     BOOL b;
2143     HRESULT hres;
2144
2145     r = stack_pop(ctx);
2146     l = stack_pop(ctx);
2147
2148     TRACE("%s >= %s\n", debugstr_jsval(l), debugstr_jsval(r));
2149
2150     hres = less_eval(ctx->script, l, r, TRUE, &b);
2151     jsval_release(l);
2152     jsval_release(r);
2153     if(FAILED(hres))
2154         return hres;
2155
2156     return stack_push(ctx, jsval_bool(b));
2157 }
2158
2159 /* ECMA-262 3rd Edition    11.4.8 */
2160 static HRESULT interp_bneg(exec_ctx_t *ctx)
2161 {
2162     jsval_t v;
2163     INT i;
2164     HRESULT hres;
2165
2166     TRACE("\n");
2167
2168     v = stack_pop(ctx);
2169     hres = to_int32(ctx->script, v, &i);
2170     jsval_release(v);
2171     if(FAILED(hres))
2172         return hres;
2173
2174     return stack_push(ctx, jsval_number(~i));
2175 }
2176
2177 /* ECMA-262 3rd Edition    11.4.9 */
2178 static HRESULT interp_neg(exec_ctx_t *ctx)
2179 {
2180     jsval_t v;
2181     BOOL b;
2182     HRESULT hres;
2183
2184     TRACE("\n");
2185
2186     v = stack_pop(ctx);
2187     hres = to_boolean(v, &b);
2188     jsval_release(v);
2189     if(FAILED(hres))
2190         return hres;
2191
2192     return stack_push(ctx, jsval_bool(!b));
2193 }
2194
2195 /* ECMA-262 3rd Edition    11.7.1 */
2196 static HRESULT interp_lshift(exec_ctx_t *ctx)
2197 {
2198     DWORD r;
2199     INT l;
2200     HRESULT hres;
2201
2202     hres = stack_pop_uint(ctx, &r);
2203     if(FAILED(hres))
2204         return hres;
2205
2206     hres = stack_pop_int(ctx, &l);
2207     if(FAILED(hres))
2208         return hres;
2209
2210     return stack_push(ctx, jsval_number(l << (r&0x1f)));
2211 }
2212
2213 /* ECMA-262 3rd Edition    11.7.2 */
2214 static HRESULT interp_rshift(exec_ctx_t *ctx)
2215 {
2216     DWORD r;
2217     INT l;
2218     HRESULT hres;
2219
2220     hres = stack_pop_uint(ctx, &r);
2221     if(FAILED(hres))
2222         return hres;
2223
2224     hres = stack_pop_int(ctx, &l);
2225     if(FAILED(hres))
2226         return hres;
2227
2228     return stack_push(ctx, jsval_number(l >> (r&0x1f)));
2229 }
2230
2231 /* ECMA-262 3rd Edition    11.7.3 */
2232 static HRESULT interp_rshift2(exec_ctx_t *ctx)
2233 {
2234     DWORD r, l;
2235     HRESULT hres;
2236
2237     hres = stack_pop_uint(ctx, &r);
2238     if(FAILED(hres))
2239         return hres;
2240
2241     hres = stack_pop_uint(ctx, &l);
2242     if(FAILED(hres))
2243         return hres;
2244
2245     return stack_push(ctx, jsval_number(l >> (r&0x1f)));
2246 }
2247
2248 /* ECMA-262 3rd Edition    11.13.1 */
2249 static HRESULT interp_assign(exec_ctx_t *ctx)
2250 {
2251     IDispatch *disp;
2252     DISPID id;
2253     jsval_t v;
2254     HRESULT hres;
2255
2256     TRACE("\n");
2257
2258     v = stack_pop(ctx);
2259
2260     disp = stack_pop_objid(ctx, &id);
2261     if(!disp) {
2262         jsval_release(v);
2263         return throw_reference_error(ctx->script, JS_E_ILLEGAL_ASSIGN, NULL);
2264     }
2265
2266     hres = disp_propput(ctx->script, disp, id, v);
2267     IDispatch_Release(disp);
2268     if(FAILED(hres)) {
2269         jsval_release(v);
2270         return hres;
2271     }
2272
2273     return stack_push(ctx, v);
2274 }
2275
2276 /* JScript extension */
2277 static HRESULT interp_assign_call(exec_ctx_t *ctx)
2278 {
2279     const unsigned argc = get_op_uint(ctx, 0);
2280     IDispatch *disp;
2281     jsval_t v;
2282     DISPID id;
2283     HRESULT hres;
2284
2285     TRACE("%u\n", argc);
2286
2287     disp = stack_topn_objid(ctx, argc+1, &id);
2288     if(!disp)
2289         return throw_reference_error(ctx->script, JS_E_ILLEGAL_ASSIGN, NULL);
2290
2291     hres = disp_call(ctx->script, disp, id, DISPATCH_PROPERTYPUT, argc+1, stack_args(ctx, argc+1), NULL);
2292     if(FAILED(hres))
2293         return hres;
2294
2295     v = stack_pop(ctx);
2296     stack_popn(ctx, argc+2);
2297     return stack_push(ctx, v);
2298 }
2299
2300 static HRESULT interp_undefined(exec_ctx_t *ctx)
2301 {
2302     TRACE("\n");
2303
2304     return stack_push(ctx, jsval_undefined());
2305 }
2306
2307 static HRESULT interp_jmp(exec_ctx_t *ctx)
2308 {
2309     const unsigned arg = get_op_uint(ctx, 0);
2310
2311     TRACE("%u\n", arg);
2312
2313     ctx->ip = arg;
2314     return S_OK;
2315 }
2316
2317 static HRESULT interp_jmp_z(exec_ctx_t *ctx)
2318 {
2319     const unsigned arg = get_op_uint(ctx, 0);
2320     BOOL b;
2321     jsval_t v;
2322     HRESULT hres;
2323
2324     TRACE("\n");
2325
2326     v = stack_pop(ctx);
2327     hres = to_boolean(v, &b);
2328     jsval_release(v);
2329     if(FAILED(hres))
2330         return hres;
2331
2332     if(b)
2333         ctx->ip++;
2334     else
2335         ctx->ip = arg;
2336     return S_OK;
2337 }
2338
2339 static HRESULT interp_pop(exec_ctx_t *ctx)
2340 {
2341     const unsigned arg = get_op_uint(ctx, 0);
2342
2343     TRACE("%u\n", arg);
2344
2345     stack_popn(ctx, arg);
2346     return S_OK;
2347 }
2348
2349 static HRESULT interp_ret(exec_ctx_t *ctx)
2350 {
2351     TRACE("\n");
2352
2353     ctx->ip = -1;
2354     return S_OK;
2355 }
2356
2357 static HRESULT interp_setret(exec_ctx_t *ctx)
2358 {
2359     TRACE("\n");
2360
2361     jsval_release(ctx->ret);
2362     ctx->ret = stack_pop(ctx);
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     }
2427
2428     return hres;
2429 }
2430
2431 static HRESULT enter_bytecode(script_ctx_t *ctx, bytecode_t *code, function_code_t *func, jsval_t *ret)
2432 {
2433     exec_ctx_t *exec_ctx = ctx->exec_ctx;
2434     except_frame_t *prev_except_frame;
2435     function_code_t *prev_func;
2436     unsigned prev_ip, prev_top;
2437     scope_chain_t *prev_scope;
2438     bytecode_t *prev_code;
2439     jsop_t op;
2440     HRESULT hres = S_OK;
2441
2442     TRACE("\n");
2443
2444     prev_top = exec_ctx->top;
2445     prev_scope = exec_ctx->scope_chain;
2446     prev_except_frame = exec_ctx->except_frame;
2447     prev_ip = exec_ctx->ip;
2448     prev_code = exec_ctx->code;
2449     prev_func = exec_ctx->func_code;
2450     exec_ctx->ip = func->instr_off;
2451     exec_ctx->except_frame = NULL;
2452     exec_ctx->code = code;
2453     exec_ctx->func_code = func;
2454
2455     while(exec_ctx->ip != -1) {
2456         op = code->instrs[exec_ctx->ip].op;
2457         hres = op_funcs[op](exec_ctx);
2458         if(FAILED(hres)) {
2459             TRACE("EXCEPTION %08x\n", hres);
2460
2461             if(!exec_ctx->except_frame)
2462                 break;
2463
2464             hres = unwind_exception(exec_ctx);
2465             if(FAILED(hres))
2466                 break;
2467         }else {
2468             exec_ctx->ip += op_move[op];
2469         }
2470     }
2471
2472     exec_ctx->ip = prev_ip;
2473     exec_ctx->except_frame = prev_except_frame;
2474     exec_ctx->code = prev_code;
2475     exec_ctx->func_code = prev_func;
2476
2477     if(FAILED(hres)) {
2478         while(exec_ctx->scope_chain != prev_scope)
2479             scope_pop(&exec_ctx->scope_chain);
2480         stack_popn(exec_ctx, exec_ctx->top-prev_top);
2481         return hres;
2482     }
2483
2484     assert(exec_ctx->top == prev_top+1 || exec_ctx->top == prev_top);
2485     assert(exec_ctx->scope_chain == prev_scope);
2486     assert(exec_ctx->top == prev_top);
2487
2488     *ret = exec_ctx->ret;
2489     exec_ctx->ret = jsval_undefined();
2490     return S_OK;
2491 }
2492
2493 HRESULT exec_source(exec_ctx_t *ctx, bytecode_t *code, function_code_t *func, BOOL from_eval, jsval_t *ret)
2494 {
2495     exec_ctx_t *prev_ctx;
2496     jsval_t val;
2497     unsigned i;
2498     HRESULT hres = S_OK;
2499
2500     for(i = 0; i < func->func_cnt; i++) {
2501         jsdisp_t *func_obj;
2502
2503         if(!func->funcs[i].name)
2504             continue;
2505
2506         hres = create_source_function(ctx->script, code, func->funcs+i, ctx->scope_chain, &func_obj);
2507         if(FAILED(hres))
2508             return hres;
2509
2510         hres = jsdisp_propput_name(ctx->var_disp, func->funcs[i].name, jsval_obj(func_obj));
2511         jsdisp_release(func_obj);
2512         if(FAILED(hres))
2513             return hres;
2514     }
2515
2516     for(i=0; i < func->var_cnt; i++) {
2517         if(!ctx->is_global || !lookup_global_members(ctx->script, func->variables[i], NULL)) {
2518             DISPID id = 0;
2519
2520             hres = jsdisp_get_id(ctx->var_disp, func->variables[i], fdexNameEnsure, &id);
2521             if(FAILED(hres))
2522                 return hres;
2523         }
2524     }
2525
2526     prev_ctx = ctx->script->exec_ctx;
2527     ctx->script->exec_ctx = ctx;
2528
2529     hres = enter_bytecode(ctx->script, code, func, &val);
2530     assert(ctx->script->exec_ctx == ctx);
2531     ctx->script->exec_ctx = prev_ctx;
2532     if(FAILED(hres))
2533         return hres;
2534
2535     if(ret)
2536         *ret = val;
2537     else
2538         jsval_release(val);
2539     return S_OK;
2540 }