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