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