msvcr110: Add _W_Gettnames implementation.
[wine.git] / dlls / jscript / engine.c
blob687b06cefede825695c5b05579d479348d2d4463
1 /*
2 * Copyright 2008,2011 Jacek Caban for CodeWeavers
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.
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.
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
19 #include "config.h"
20 #include "wine/port.h"
22 #include <math.h>
23 #include <assert.h>
25 #include "jscript.h"
26 #include "engine.h"
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
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};
40 struct _except_frame_t {
41 unsigned stack_top;
42 scope_chain_t *scope;
43 unsigned catch_off;
44 BSTR ident;
46 except_frame_t *next;
49 typedef struct {
50 enum {
51 EXPRVAL_JSVAL,
52 EXPRVAL_IDREF,
53 EXPRVAL_INVALID
54 } type;
55 union {
56 jsval_t val;
57 struct {
58 IDispatch *disp;
59 DISPID id;
60 } idref;
61 } u;
62 } exprval_t;
64 static HRESULT stack_push(exec_ctx_t *ctx, jsval_t v)
66 if(!ctx->stack_size) {
67 ctx->stack = heap_alloc(16*sizeof(*ctx->stack));
68 if(!ctx->stack)
69 return E_OUTOFMEMORY;
70 ctx->stack_size = 16;
71 }else if(ctx->stack_size == ctx->top) {
72 jsval_t *new_stack;
74 new_stack = heap_realloc(ctx->stack, ctx->stack_size*2*sizeof(*new_stack));
75 if(!new_stack) {
76 jsval_release(v);
77 return E_OUTOFMEMORY;
80 ctx->stack = new_stack;
81 ctx->stack_size *= 2;
84 ctx->stack[ctx->top++] = v;
85 return S_OK;
88 static inline HRESULT stack_push_string(exec_ctx_t *ctx, const WCHAR *str)
90 jsstr_t *v;
92 v = jsstr_alloc(str);
93 if(!v)
94 return E_OUTOFMEMORY;
96 return stack_push(ctx, jsval_string(v));
99 static HRESULT stack_push_objid(exec_ctx_t *ctx, IDispatch *disp, DISPID id)
101 HRESULT hres;
103 hres = stack_push(ctx, jsval_disp(disp));
104 if(FAILED(hres))
105 return hres;
107 return stack_push(ctx, jsval_number(id));
110 static inline jsval_t stack_top(exec_ctx_t *ctx)
112 assert(ctx->top);
113 return ctx->stack[ctx->top-1];
116 static inline jsval_t stack_topn(exec_ctx_t *ctx, unsigned n)
118 assert(ctx->top > n);
119 return ctx->stack[ctx->top-1-n];
122 static inline jsval_t *stack_args(exec_ctx_t *ctx, unsigned n)
124 if(!n)
125 return NULL;
126 assert(ctx->top > n-1);
127 return ctx->stack + ctx->top-n;
130 static inline jsval_t stack_pop(exec_ctx_t *ctx)
132 assert(ctx->top);
133 return ctx->stack[--ctx->top];
136 static void stack_popn(exec_ctx_t *ctx, unsigned n)
138 while(n--)
139 jsval_release(stack_pop(ctx));
142 static HRESULT stack_pop_number(exec_ctx_t *ctx, double *r)
144 jsval_t v;
145 HRESULT hres;
147 v = stack_pop(ctx);
148 hres = to_number(ctx->script, v, r);
149 jsval_release(v);
150 return hres;
153 static HRESULT stack_pop_object(exec_ctx_t *ctx, IDispatch **r)
155 jsval_t v;
156 HRESULT hres;
158 v = stack_pop(ctx);
159 if(is_object_instance(v)) {
160 if(!get_object(v))
161 return throw_type_error(ctx->script, JS_E_OBJECT_REQUIRED, NULL);
162 *r = get_object(v);
163 return S_OK;
166 hres = to_object(ctx->script, v, r);
167 jsval_release(v);
168 return hres;
171 static inline HRESULT stack_pop_int(exec_ctx_t *ctx, INT *r)
173 return to_int32(ctx->script, stack_pop(ctx), r);
176 static inline HRESULT stack_pop_uint(exec_ctx_t *ctx, DWORD *r)
178 return to_uint32(ctx->script, stack_pop(ctx), r);
181 static inline IDispatch *stack_pop_objid(exec_ctx_t *ctx, DISPID *id)
183 assert(is_number(stack_top(ctx)) && is_object_instance(stack_topn(ctx, 1)));
185 *id = get_number(stack_pop(ctx));
186 return get_object(stack_pop(ctx));
189 static inline IDispatch *stack_topn_objid(exec_ctx_t *ctx, unsigned n, DISPID *id)
191 assert(is_number(stack_topn(ctx, n)) && is_object_instance(stack_topn(ctx, n+1)));
193 *id = get_number(stack_topn(ctx, n));
194 return get_object(stack_topn(ctx, n+1));
197 static void exprval_release(exprval_t *val)
199 switch(val->type) {
200 case EXPRVAL_JSVAL:
201 jsval_release(val->u.val);
202 return;
203 case EXPRVAL_IDREF:
204 if(val->u.idref.disp)
205 IDispatch_Release(val->u.idref.disp);
206 return;
207 case EXPRVAL_INVALID:
208 return;
212 /* ECMA-262 3rd Edition 8.7.1 */
213 static HRESULT exprval_to_value(script_ctx_t *ctx, exprval_t *val, jsval_t *ret)
215 switch(val->type) {
216 case EXPRVAL_JSVAL:
217 *ret = val->u.val;
218 val->u.val = jsval_undefined();
219 return S_OK;
220 case EXPRVAL_IDREF:
221 if(!val->u.idref.disp) {
222 FIXME("throw ReferenceError\n");
223 return E_FAIL;
226 return disp_propget(ctx, val->u.idref.disp, val->u.idref.id, ret);
227 case EXPRVAL_INVALID:
228 assert(0);
231 ERR("type %d\n", val->type);
232 return E_FAIL;
235 static void exprval_set_idref(exprval_t *val, IDispatch *disp, DISPID id)
237 val->type = EXPRVAL_IDREF;
238 val->u.idref.disp = disp;
239 val->u.idref.id = id;
241 if(disp)
242 IDispatch_AddRef(disp);
245 HRESULT scope_push(scope_chain_t *scope, jsdisp_t *jsobj, IDispatch *obj, scope_chain_t **ret)
247 scope_chain_t *new_scope;
249 new_scope = heap_alloc(sizeof(scope_chain_t));
250 if(!new_scope)
251 return E_OUTOFMEMORY;
253 new_scope->ref = 1;
255 IDispatch_AddRef(obj);
256 new_scope->jsobj = jsobj;
257 new_scope->obj = obj;
259 if(scope) {
260 scope_addref(scope);
261 new_scope->next = scope;
262 }else {
263 new_scope->next = NULL;
266 *ret = new_scope;
267 return S_OK;
270 static void scope_pop(scope_chain_t **scope)
272 scope_chain_t *tmp;
274 tmp = *scope;
275 *scope = tmp->next;
276 scope_release(tmp);
279 void clear_ei(script_ctx_t *ctx)
281 memset(&ctx->ei.ei, 0, sizeof(ctx->ei.ei));
282 jsval_release(ctx->ei.val);
283 ctx->ei.val = jsval_undefined();
286 void scope_release(scope_chain_t *scope)
288 if(--scope->ref)
289 return;
291 if(scope->next)
292 scope_release(scope->next);
294 IDispatch_Release(scope->obj);
295 heap_free(scope);
298 HRESULT create_exec_ctx(script_ctx_t *script_ctx, IDispatch *this_obj, jsdisp_t *var_disp,
299 scope_chain_t *scope, BOOL is_global, exec_ctx_t **ret)
301 exec_ctx_t *ctx;
303 ctx = heap_alloc_zero(sizeof(exec_ctx_t));
304 if(!ctx)
305 return E_OUTOFMEMORY;
307 ctx->ref = 1;
308 ctx->is_global = is_global;
309 ctx->ret = jsval_undefined();
311 /* ECMA-262 3rd Edition 11.2.3.7 */
312 if(this_obj) {
313 jsdisp_t *jsthis;
315 jsthis = iface_to_jsdisp((IUnknown*)this_obj);
316 if(jsthis) {
317 if(jsthis->builtin_info->class == JSCLASS_GLOBAL || jsthis->builtin_info->class == JSCLASS_NONE)
318 this_obj = NULL;
319 jsdisp_release(jsthis);
323 if(this_obj)
324 ctx->this_obj = this_obj;
325 else if(script_ctx->host_global)
326 ctx->this_obj = script_ctx->host_global;
327 else
328 ctx->this_obj = to_disp(script_ctx->global);
329 IDispatch_AddRef(ctx->this_obj);
331 jsdisp_addref(var_disp);
332 ctx->var_disp = var_disp;
334 script_addref(script_ctx);
335 ctx->script = script_ctx;
337 if(scope) {
338 scope_addref(scope);
339 ctx->scope_chain = scope;
342 *ret = ctx;
343 return S_OK;
346 void exec_release(exec_ctx_t *ctx)
348 if(--ctx->ref)
349 return;
351 if(ctx->scope_chain)
352 scope_release(ctx->scope_chain);
353 if(ctx->var_disp)
354 jsdisp_release(ctx->var_disp);
355 if(ctx->this_obj)
356 IDispatch_Release(ctx->this_obj);
357 if(ctx->script)
358 script_release(ctx->script);
359 jsval_release(ctx->ret);
360 heap_free(ctx->stack);
361 heap_free(ctx);
364 static HRESULT disp_get_id(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name, BSTR name_bstr, DWORD flags, DISPID *id)
366 IDispatchEx *dispex;
367 jsdisp_t *jsdisp;
368 BSTR bstr;
369 HRESULT hres;
371 jsdisp = iface_to_jsdisp((IUnknown*)disp);
372 if(jsdisp) {
373 hres = jsdisp_get_id(jsdisp, name, flags, id);
374 jsdisp_release(jsdisp);
375 return hres;
378 if(name_bstr) {
379 bstr = name_bstr;
380 }else {
381 bstr = SysAllocString(name);
382 if(!bstr)
383 return E_OUTOFMEMORY;
386 *id = 0;
387 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
388 if(SUCCEEDED(hres)) {
389 hres = IDispatchEx_GetDispID(dispex, bstr, make_grfdex(ctx, flags|fdexNameCaseSensitive), id);
390 IDispatchEx_Release(dispex);
391 }else {
392 TRACE("using IDispatch\n");
393 hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, id);
396 if(name_bstr != bstr)
397 SysFreeString(bstr);
398 return hres;
401 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, BOOL *ret)
403 IObjectIdentity *identity;
404 IUnknown *unk1, *unk2;
405 HRESULT hres;
407 if(disp1 == disp2) {
408 *ret = TRUE;
409 return S_OK;
412 if(!disp1 || !disp2) {
413 *ret = FALSE;
414 return S_OK;
417 hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
418 if(FAILED(hres))
419 return hres;
421 hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
422 if(FAILED(hres)) {
423 IUnknown_Release(unk1);
424 return hres;
427 if(unk1 == unk2) {
428 *ret = TRUE;
429 }else {
430 hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
431 if(SUCCEEDED(hres)) {
432 hres = IObjectIdentity_IsEqualObject(identity, unk2);
433 IObjectIdentity_Release(identity);
434 *ret = hres == S_OK;
435 }else {
436 *ret = FALSE;
440 IUnknown_Release(unk1);
441 IUnknown_Release(unk2);
442 return S_OK;
445 /* ECMA-262 3rd Edition 11.9.6 */
446 static HRESULT equal2_values(jsval_t lval, jsval_t rval, BOOL *ret)
448 jsval_type_t type = jsval_type(lval);
450 TRACE("\n");
452 if(type != jsval_type(rval)) {
453 if(is_null_instance(lval))
454 *ret = is_null_instance(rval);
455 else
456 *ret = FALSE;
457 return S_OK;
460 switch(type) {
461 case JSV_UNDEFINED:
462 case JSV_NULL:
463 *ret = TRUE;
464 break;
465 case JSV_OBJECT:
466 return disp_cmp(get_object(lval), get_object(rval), ret);
467 case JSV_STRING:
468 *ret = jsstr_eq(get_string(lval), get_string(rval));
469 break;
470 case JSV_NUMBER:
471 *ret = get_number(lval) == get_number(rval);
472 break;
473 case JSV_BOOL:
474 *ret = !get_bool(lval) == !get_bool(rval);
475 break;
476 case JSV_VARIANT:
477 FIXME("VARIANT not implemented\n");
478 return E_NOTIMPL;
481 return S_OK;
484 static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
486 named_item_t *item;
487 DISPID id;
488 HRESULT hres;
490 for(item = ctx->named_items; item; item = item->next) {
491 if(item->flags & SCRIPTITEM_GLOBALMEMBERS) {
492 hres = disp_get_id(ctx, item->disp, identifier, identifier, 0, &id);
493 if(SUCCEEDED(hres)) {
494 if(ret)
495 exprval_set_idref(ret, item->disp, id);
496 return TRUE;
501 return FALSE;
504 /* ECMA-262 3rd Edition 10.1.4 */
505 static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
507 scope_chain_t *scope;
508 named_item_t *item;
509 DISPID id = 0;
510 HRESULT hres;
512 TRACE("%s\n", debugstr_w(identifier));
514 if(ctx->exec_ctx) {
515 for(scope = ctx->exec_ctx->scope_chain; scope; scope = scope->next) {
516 if(scope->jsobj)
517 hres = jsdisp_get_id(scope->jsobj, identifier, fdexNameImplicit, &id);
518 else
519 hres = disp_get_id(ctx, scope->obj, identifier, identifier, fdexNameImplicit, &id);
520 if(SUCCEEDED(hres)) {
521 exprval_set_idref(ret, scope->obj, id);
522 return S_OK;
527 hres = jsdisp_get_id(ctx->global, identifier, 0, &id);
528 if(SUCCEEDED(hres)) {
529 exprval_set_idref(ret, to_disp(ctx->global), id);
530 return S_OK;
533 for(item = ctx->named_items; item; item = item->next) {
534 if((item->flags & SCRIPTITEM_ISVISIBLE) && !strcmpW(item->name, identifier)) {
535 if(!item->disp) {
536 IUnknown *unk;
538 if(!ctx->site)
539 break;
541 hres = IActiveScriptSite_GetItemInfo(ctx->site, identifier,
542 SCRIPTINFO_IUNKNOWN, &unk, NULL);
543 if(FAILED(hres)) {
544 WARN("GetItemInfo failed: %08x\n", hres);
545 break;
548 hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp);
549 IUnknown_Release(unk);
550 if(FAILED(hres)) {
551 WARN("object does not implement IDispatch\n");
552 break;
556 IDispatch_AddRef(item->disp);
557 ret->type = EXPRVAL_JSVAL;
558 ret->u.val = jsval_disp(item->disp);
559 return S_OK;
563 if(lookup_global_members(ctx, identifier, ret))
564 return S_OK;
566 ret->type = EXPRVAL_INVALID;
567 return S_OK;
570 static inline BSTR get_op_bstr(exec_ctx_t *ctx, int i){
571 return ctx->code->instrs[ctx->ip].u.arg[i].bstr;
574 static inline unsigned get_op_uint(exec_ctx_t *ctx, int i){
575 return ctx->code->instrs[ctx->ip].u.arg[i].uint;
578 static inline unsigned get_op_int(exec_ctx_t *ctx, int i){
579 return ctx->code->instrs[ctx->ip].u.arg[i].lng;
582 static inline jsstr_t *get_op_str(exec_ctx_t *ctx, int i){
583 return ctx->code->instrs[ctx->ip].u.arg[i].str;
586 static inline double get_op_double(exec_ctx_t *ctx){
587 return ctx->code->instrs[ctx->ip].u.dbl;
590 /* ECMA-262 3rd Edition 12.2 */
591 static HRESULT interp_var_set(exec_ctx_t *ctx)
593 const BSTR name = get_op_bstr(ctx, 0);
594 jsval_t val;
595 HRESULT hres;
597 TRACE("%s\n", debugstr_w(name));
599 val = stack_pop(ctx);
600 hres = jsdisp_propput_name(ctx->var_disp, name, val);
601 jsval_release(val);
602 return hres;
605 /* ECMA-262 3rd Edition 12.6.4 */
606 static HRESULT interp_forin(exec_ctx_t *ctx)
608 const HRESULT arg = get_op_uint(ctx, 0);
609 IDispatch *var_obj, *obj = NULL;
610 IDispatchEx *dispex;
611 DISPID id, var_id;
612 BSTR name = NULL;
613 HRESULT hres;
615 TRACE("\n");
617 assert(is_number(stack_top(ctx)));
618 id = get_number(stack_top(ctx));
620 var_obj = stack_topn_objid(ctx, 1, &var_id);
621 if(!var_obj) {
622 FIXME("invalid ref\n");
623 return E_FAIL;
626 if(is_object_instance(stack_topn(ctx, 3)))
627 obj = get_object(stack_topn(ctx, 3));
629 if(obj) {
630 hres = IDispatch_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
631 if(SUCCEEDED(hres)) {
632 hres = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, id, &id);
633 if(hres == S_OK)
634 hres = IDispatchEx_GetMemberName(dispex, id, &name);
635 IDispatchEx_Release(dispex);
636 if(FAILED(hres))
637 return hres;
638 }else {
639 TRACE("No IDispatchEx\n");
643 if(name) {
644 jsstr_t *str;
646 str = jsstr_alloc_len(name, SysStringLen(name));
647 SysFreeString(name);
648 if(!str)
649 return E_OUTOFMEMORY;
651 stack_pop(ctx);
652 stack_push(ctx, jsval_number(id)); /* safe, just after pop() */
654 hres = disp_propput(ctx->script, var_obj, var_id, jsval_string(str));
655 jsstr_release(str);
656 if(FAILED(hres))
657 return hres;
659 ctx->ip++;
660 }else {
661 stack_popn(ctx, 4);
662 ctx->ip = arg;
664 return S_OK;
667 /* ECMA-262 3rd Edition 12.10 */
668 static HRESULT interp_push_scope(exec_ctx_t *ctx)
670 IDispatch *disp;
671 jsval_t v;
672 HRESULT hres;
674 TRACE("\n");
676 v = stack_pop(ctx);
677 hres = to_object(ctx->script, v, &disp);
678 jsval_release(v);
679 if(FAILED(hres))
680 return hres;
682 hres = scope_push(ctx->scope_chain, to_jsdisp(disp), disp, &ctx->scope_chain);
683 IDispatch_Release(disp);
684 return hres;
687 /* ECMA-262 3rd Edition 12.10 */
688 static HRESULT interp_pop_scope(exec_ctx_t *ctx)
690 TRACE("\n");
692 scope_pop(&ctx->scope_chain);
693 return S_OK;
696 /* ECMA-262 3rd Edition 12.13 */
697 static HRESULT interp_case(exec_ctx_t *ctx)
699 const unsigned arg = get_op_uint(ctx, 0);
700 jsval_t v;
701 BOOL b;
702 HRESULT hres;
704 TRACE("\n");
706 v = stack_pop(ctx);
707 hres = equal2_values(stack_top(ctx), v, &b);
708 jsval_release(v);
709 if(FAILED(hres))
710 return hres;
712 if(b) {
713 stack_popn(ctx, 1);
714 ctx->ip = arg;
715 }else {
716 ctx->ip++;
718 return S_OK;
721 /* ECMA-262 3rd Edition 12.13 */
722 static HRESULT interp_throw(exec_ctx_t *ctx)
724 TRACE("\n");
726 jsval_release(ctx->script->ei.val);
727 ctx->script->ei.val = stack_pop(ctx);
728 return DISP_E_EXCEPTION;
731 static HRESULT interp_throw_ref(exec_ctx_t *ctx)
733 const HRESULT arg = get_op_uint(ctx, 0);
735 TRACE("%08x\n", arg);
737 return throw_reference_error(ctx->script, arg, NULL);
740 static HRESULT interp_throw_type(exec_ctx_t *ctx)
742 const HRESULT hres = get_op_uint(ctx, 0);
743 jsstr_t *str = get_op_str(ctx, 1);
744 const WCHAR *ptr;
746 TRACE("%08x %s\n", hres, debugstr_jsstr(str));
748 ptr = jsstr_flatten(str);
749 return ptr ? throw_type_error(ctx->script, hres, ptr) : E_OUTOFMEMORY;
752 /* ECMA-262 3rd Edition 12.14 */
753 static HRESULT interp_push_except(exec_ctx_t *ctx)
755 const unsigned arg1 = get_op_uint(ctx, 0);
756 const BSTR arg2 = get_op_bstr(ctx, 1);
757 except_frame_t *except;
758 unsigned stack_top;
760 TRACE("\n");
762 stack_top = ctx->top;
764 if(!arg2) {
765 HRESULT hres;
767 hres = stack_push(ctx, jsval_bool(TRUE));
768 if(FAILED(hres))
769 return hres;
770 hres = stack_push(ctx, jsval_bool(TRUE));
771 if(FAILED(hres))
772 return hres;
775 except = heap_alloc(sizeof(*except));
776 if(!except)
777 return E_OUTOFMEMORY;
779 except->stack_top = stack_top;
780 except->scope = ctx->scope_chain;
781 except->catch_off = arg1;
782 except->ident = arg2;
783 except->next = ctx->except_frame;
784 ctx->except_frame = except;
785 return S_OK;
788 /* ECMA-262 3rd Edition 12.14 */
789 static HRESULT interp_pop_except(exec_ctx_t *ctx)
791 except_frame_t *except;
793 TRACE("\n");
795 except = ctx->except_frame;
796 assert(except != NULL);
798 ctx->except_frame = except->next;
799 heap_free(except);
800 return S_OK;
803 /* ECMA-262 3rd Edition 12.14 */
804 static HRESULT interp_end_finally(exec_ctx_t *ctx)
806 jsval_t v;
808 TRACE("\n");
810 v = stack_pop(ctx);
811 assert(is_bool(v));
813 if(!get_bool(v)) {
814 TRACE("passing exception\n");
816 ctx->script->ei.val = stack_pop(ctx);
817 return DISP_E_EXCEPTION;
820 stack_pop(ctx);
821 return S_OK;
824 /* ECMA-262 3rd Edition 13 */
825 static HRESULT interp_func(exec_ctx_t *ctx)
827 unsigned func_idx = get_op_uint(ctx, 0);
828 jsdisp_t *dispex;
829 HRESULT hres;
831 TRACE("%d\n", func_idx);
833 hres = create_source_function(ctx->script, ctx->code, ctx->func_code->funcs+func_idx,
834 ctx->scope_chain, &dispex);
835 if(FAILED(hres))
836 return hres;
838 return stack_push(ctx, jsval_obj(dispex));
841 /* ECMA-262 3rd Edition 11.2.1 */
842 static HRESULT interp_array(exec_ctx_t *ctx)
844 jsstr_t *name_str;
845 const WCHAR *name;
846 jsval_t v, namev;
847 IDispatch *obj;
848 DISPID id;
849 HRESULT hres;
851 TRACE("\n");
853 namev = stack_pop(ctx);
855 hres = stack_pop_object(ctx, &obj);
856 if(FAILED(hres)) {
857 jsval_release(namev);
858 return hres;
861 hres = to_flat_string(ctx->script, namev, &name_str, &name);
862 jsval_release(namev);
863 if(FAILED(hres)) {
864 IDispatch_Release(obj);
865 return hres;
868 hres = disp_get_id(ctx->script, obj, name, NULL, 0, &id);
869 jsstr_release(name_str);
870 if(SUCCEEDED(hres)) {
871 hres = disp_propget(ctx->script, obj, id, &v);
872 }else if(hres == DISP_E_UNKNOWNNAME) {
873 v = jsval_undefined();
874 hres = S_OK;
876 IDispatch_Release(obj);
877 if(FAILED(hres))
878 return hres;
880 return stack_push(ctx, v);
883 /* ECMA-262 3rd Edition 11.2.1 */
884 static HRESULT interp_member(exec_ctx_t *ctx)
886 const BSTR arg = get_op_bstr(ctx, 0);
887 IDispatch *obj;
888 jsval_t v;
889 DISPID id;
890 HRESULT hres;
892 TRACE("\n");
894 hres = stack_pop_object(ctx, &obj);
895 if(FAILED(hres))
896 return hres;
898 hres = disp_get_id(ctx->script, obj, arg, arg, 0, &id);
899 if(SUCCEEDED(hres)) {
900 hres = disp_propget(ctx->script, obj, id, &v);
901 }else if(hres == DISP_E_UNKNOWNNAME) {
902 v = jsval_undefined();
903 hres = S_OK;
905 IDispatch_Release(obj);
906 if(FAILED(hres))
907 return hres;
909 return stack_push(ctx, v);
912 /* ECMA-262 3rd Edition 11.2.1 */
913 static HRESULT interp_memberid(exec_ctx_t *ctx)
915 const unsigned arg = get_op_uint(ctx, 0);
916 jsval_t objv, namev;
917 const WCHAR *name;
918 jsstr_t *name_str;
919 IDispatch *obj;
920 DISPID id;
921 HRESULT hres;
923 TRACE("%x\n", arg);
925 namev = stack_pop(ctx);
926 objv = stack_pop(ctx);
928 hres = to_object(ctx->script, objv, &obj);
929 jsval_release(objv);
930 if(SUCCEEDED(hres)) {
931 hres = to_flat_string(ctx->script, namev, &name_str, &name);
932 if(FAILED(hres))
933 IDispatch_Release(obj);
935 jsval_release(namev);
936 if(FAILED(hres))
937 return hres;
939 hres = disp_get_id(ctx->script, obj, name, NULL, arg, &id);
940 jsstr_release(name_str);
941 if(FAILED(hres)) {
942 IDispatch_Release(obj);
943 if(hres == DISP_E_UNKNOWNNAME && !(arg & fdexNameEnsure)) {
944 obj = NULL;
945 id = JS_E_INVALID_PROPERTY;
946 }else {
947 ERR("failed %08x\n", hres);
948 return hres;
952 return stack_push_objid(ctx, obj, id);
955 /* ECMA-262 3rd Edition 11.2.1 */
956 static HRESULT interp_refval(exec_ctx_t *ctx)
958 IDispatch *disp;
959 jsval_t v;
960 DISPID id;
961 HRESULT hres;
963 TRACE("\n");
965 disp = stack_topn_objid(ctx, 0, &id);
966 if(!disp)
967 return throw_reference_error(ctx->script, JS_E_ILLEGAL_ASSIGN, NULL);
969 hres = disp_propget(ctx->script, disp, id, &v);
970 if(FAILED(hres))
971 return hres;
973 return stack_push(ctx, v);
976 /* ECMA-262 3rd Edition 11.2.2 */
977 static HRESULT interp_new(exec_ctx_t *ctx)
979 const unsigned argc = get_op_uint(ctx, 0);
980 jsval_t r, constr;
981 HRESULT hres;
983 TRACE("%d\n", argc);
985 constr = stack_topn(ctx, argc);
987 /* NOTE: Should use to_object here */
989 if(is_null(constr))
990 return throw_type_error(ctx->script, JS_E_OBJECT_EXPECTED, NULL);
991 else if(!is_object_instance(constr))
992 return throw_type_error(ctx->script, JS_E_INVALID_ACTION, NULL);
993 else if(!get_object(constr))
994 return throw_type_error(ctx->script, JS_E_INVALID_PROPERTY, NULL);
996 hres = disp_call_value(ctx->script, get_object(constr), NULL, DISPATCH_CONSTRUCT, argc, stack_args(ctx, argc), &r);
997 if(FAILED(hres))
998 return hres;
1000 stack_popn(ctx, argc+1);
1001 return stack_push(ctx, r);
1004 /* ECMA-262 3rd Edition 11.2.3 */
1005 static HRESULT interp_call(exec_ctx_t *ctx)
1007 const unsigned argn = get_op_uint(ctx, 0);
1008 const int do_ret = get_op_int(ctx, 1);
1009 jsval_t r, obj;
1010 HRESULT hres;
1012 TRACE("%d %d\n", argn, do_ret);
1014 obj = stack_topn(ctx, argn);
1015 if(!is_object_instance(obj))
1016 return throw_type_error(ctx->script, JS_E_INVALID_PROPERTY, NULL);
1018 hres = disp_call_value(ctx->script, get_object(obj), NULL, DISPATCH_METHOD, argn, stack_args(ctx, argn),
1019 do_ret ? &r : NULL);
1020 if(FAILED(hres))
1021 return hres;
1023 stack_popn(ctx, argn+1);
1024 return do_ret ? stack_push(ctx, r) : S_OK;
1027 /* ECMA-262 3rd Edition 11.2.3 */
1028 static HRESULT interp_call_member(exec_ctx_t *ctx)
1030 const unsigned argn = get_op_uint(ctx, 0);
1031 const int do_ret = get_op_int(ctx, 1);
1032 IDispatch *obj;
1033 jsval_t r;
1034 DISPID id;
1035 HRESULT hres;
1037 TRACE("%d %d\n", argn, do_ret);
1039 obj = stack_topn_objid(ctx, argn, &id);
1040 if(!obj)
1041 return throw_type_error(ctx->script, id, NULL);
1043 hres = disp_call(ctx->script, obj, id, DISPATCH_METHOD, argn, stack_args(ctx, argn), do_ret ? &r : NULL);
1044 if(FAILED(hres))
1045 return hres;
1047 stack_popn(ctx, argn+2);
1048 return do_ret ? stack_push(ctx, r) : S_OK;
1052 /* ECMA-262 3rd Edition 11.1.1 */
1053 static HRESULT interp_this(exec_ctx_t *ctx)
1055 TRACE("\n");
1057 IDispatch_AddRef(ctx->this_obj);
1058 return stack_push(ctx, jsval_disp(ctx->this_obj));
1061 /* ECMA-262 3rd Edition 10.1.4 */
1062 static HRESULT interp_ident(exec_ctx_t *ctx)
1064 const BSTR arg = get_op_bstr(ctx, 0);
1065 exprval_t exprval;
1066 jsval_t v;
1067 HRESULT hres;
1069 TRACE("%s\n", debugstr_w(arg));
1071 hres = identifier_eval(ctx->script, arg, &exprval);
1072 if(FAILED(hres))
1073 return hres;
1075 if(exprval.type == EXPRVAL_INVALID)
1076 return throw_type_error(ctx->script, JS_E_UNDEFINED_VARIABLE, arg);
1078 hres = exprval_to_value(ctx->script, &exprval, &v);
1079 exprval_release(&exprval);
1080 if(FAILED(hres))
1081 return hres;
1083 return stack_push(ctx, v);
1086 /* ECMA-262 3rd Edition 10.1.4 */
1087 static HRESULT interp_identid(exec_ctx_t *ctx)
1089 const BSTR arg = get_op_bstr(ctx, 0);
1090 const unsigned flags = get_op_uint(ctx, 1);
1091 exprval_t exprval;
1092 HRESULT hres;
1094 TRACE("%s %x\n", debugstr_w(arg), flags);
1096 hres = identifier_eval(ctx->script, arg, &exprval);
1097 if(FAILED(hres))
1098 return hres;
1100 if(exprval.type == EXPRVAL_INVALID && (flags & fdexNameEnsure)) {
1101 DISPID id;
1103 hres = jsdisp_get_id(ctx->script->global, arg, fdexNameEnsure, &id);
1104 if(FAILED(hres))
1105 return hres;
1107 exprval_set_idref(&exprval, to_disp(ctx->script->global), id);
1110 if(exprval.type != EXPRVAL_IDREF) {
1111 WARN("invalid ref\n");
1112 exprval_release(&exprval);
1113 return stack_push_objid(ctx, NULL, JS_E_OBJECT_EXPECTED);
1116 return stack_push_objid(ctx, exprval.u.idref.disp, exprval.u.idref.id);
1119 /* ECMA-262 3rd Edition 7.8.1 */
1120 static HRESULT interp_null(exec_ctx_t *ctx)
1122 TRACE("\n");
1124 return stack_push(ctx, jsval_null());
1127 /* ECMA-262 3rd Edition 7.8.2 */
1128 static HRESULT interp_bool(exec_ctx_t *ctx)
1130 const int arg = get_op_int(ctx, 0);
1132 TRACE("%s\n", arg ? "true" : "false");
1134 return stack_push(ctx, jsval_bool(arg));
1137 /* ECMA-262 3rd Edition 7.8.3 */
1138 static HRESULT interp_int(exec_ctx_t *ctx)
1140 const int arg = get_op_int(ctx, 0);
1142 TRACE("%d\n", arg);
1144 return stack_push(ctx, jsval_number(arg));
1147 /* ECMA-262 3rd Edition 7.8.3 */
1148 static HRESULT interp_double(exec_ctx_t *ctx)
1150 const double arg = get_op_double(ctx);
1152 TRACE("%lf\n", arg);
1154 return stack_push(ctx, jsval_number(arg));
1157 /* ECMA-262 3rd Edition 7.8.4 */
1158 static HRESULT interp_str(exec_ctx_t *ctx)
1160 jsstr_t *str = get_op_str(ctx, 0);
1162 TRACE("%s\n", debugstr_jsstr(str));
1164 return stack_push(ctx, jsval_string(jsstr_addref(str)));
1167 /* ECMA-262 3rd Edition 7.8 */
1168 static HRESULT interp_regexp(exec_ctx_t *ctx)
1170 jsstr_t *source = get_op_str(ctx, 0);
1171 const unsigned flags = get_op_uint(ctx, 1);
1172 jsdisp_t *regexp;
1173 HRESULT hres;
1175 TRACE("%s %x\n", debugstr_jsstr(source), flags);
1177 hres = create_regexp(ctx->script, source, flags, &regexp);
1178 if(FAILED(hres))
1179 return hres;
1181 return stack_push(ctx, jsval_obj(regexp));
1184 /* ECMA-262 3rd Edition 11.1.4 */
1185 static HRESULT interp_carray(exec_ctx_t *ctx)
1187 const unsigned arg = get_op_uint(ctx, 0);
1188 jsdisp_t *array;
1189 jsval_t val;
1190 unsigned i;
1191 HRESULT hres;
1193 TRACE("%u\n", arg);
1195 hres = create_array(ctx->script, arg, &array);
1196 if(FAILED(hres))
1197 return hres;
1199 i = arg;
1200 while(i--) {
1201 val = stack_pop(ctx);
1202 hres = jsdisp_propput_idx(array, i, val);
1203 jsval_release(val);
1204 if(FAILED(hres)) {
1205 jsdisp_release(array);
1206 return hres;
1210 return stack_push(ctx, jsval_obj(array));
1213 /* ECMA-262 3rd Edition 11.1.5 */
1214 static HRESULT interp_new_obj(exec_ctx_t *ctx)
1216 jsdisp_t *obj;
1217 HRESULT hres;
1219 TRACE("\n");
1221 hres = create_object(ctx->script, NULL, &obj);
1222 if(FAILED(hres))
1223 return hres;
1225 return stack_push(ctx, jsval_obj(obj));
1228 /* ECMA-262 3rd Edition 11.1.5 */
1229 static HRESULT interp_obj_prop(exec_ctx_t *ctx)
1231 const BSTR name = get_op_bstr(ctx, 0);
1232 jsdisp_t *obj;
1233 jsval_t val;
1234 HRESULT hres;
1236 TRACE("%s\n", debugstr_w(name));
1238 val = stack_pop(ctx);
1240 assert(is_object_instance(stack_top(ctx)));
1241 obj = as_jsdisp(get_object(stack_top(ctx)));
1243 hres = jsdisp_propput_name(obj, name, val);
1244 jsval_release(val);
1245 return hres;
1248 /* ECMA-262 3rd Edition 11.11 */
1249 static HRESULT interp_cnd_nz(exec_ctx_t *ctx)
1251 const unsigned arg = get_op_uint(ctx, 0);
1252 BOOL b;
1253 HRESULT hres;
1255 TRACE("\n");
1257 hres = to_boolean(stack_top(ctx), &b);
1258 if(FAILED(hres))
1259 return hres;
1261 if(b) {
1262 ctx->ip = arg;
1263 }else {
1264 stack_popn(ctx, 1);
1265 ctx->ip++;
1267 return S_OK;
1270 /* ECMA-262 3rd Edition 11.11 */
1271 static HRESULT interp_cnd_z(exec_ctx_t *ctx)
1273 const unsigned arg = get_op_uint(ctx, 0);
1274 BOOL b;
1275 HRESULT hres;
1277 TRACE("\n");
1279 hres = to_boolean(stack_top(ctx), &b);
1280 if(FAILED(hres))
1281 return hres;
1283 if(b) {
1284 stack_popn(ctx, 1);
1285 ctx->ip++;
1286 }else {
1287 ctx->ip = arg;
1289 return S_OK;
1292 /* ECMA-262 3rd Edition 11.10 */
1293 static HRESULT interp_or(exec_ctx_t *ctx)
1295 INT l, r;
1296 HRESULT hres;
1298 TRACE("\n");
1300 hres = stack_pop_int(ctx, &r);
1301 if(FAILED(hres))
1302 return hres;
1304 hres = stack_pop_int(ctx, &l);
1305 if(FAILED(hres))
1306 return hres;
1308 return stack_push(ctx, jsval_number(l|r));
1311 /* ECMA-262 3rd Edition 11.10 */
1312 static HRESULT interp_xor(exec_ctx_t *ctx)
1314 INT l, r;
1315 HRESULT hres;
1317 TRACE("\n");
1319 hres = stack_pop_int(ctx, &r);
1320 if(FAILED(hres))
1321 return hres;
1323 hres = stack_pop_int(ctx, &l);
1324 if(FAILED(hres))
1325 return hres;
1327 return stack_push(ctx, jsval_number(l^r));
1330 /* ECMA-262 3rd Edition 11.10 */
1331 static HRESULT interp_and(exec_ctx_t *ctx)
1333 INT l, r;
1334 HRESULT hres;
1336 TRACE("\n");
1338 hres = stack_pop_int(ctx, &r);
1339 if(FAILED(hres))
1340 return hres;
1342 hres = stack_pop_int(ctx, &l);
1343 if(FAILED(hres))
1344 return hres;
1346 return stack_push(ctx, jsval_number(l&r));
1349 /* ECMA-262 3rd Edition 11.8.6 */
1350 static HRESULT interp_instanceof(exec_ctx_t *ctx)
1352 jsdisp_t *obj, *iter, *tmp = NULL;
1353 jsval_t prot, v;
1354 BOOL ret = FALSE;
1355 HRESULT hres;
1357 static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0};
1359 v = stack_pop(ctx);
1360 if(!is_object_instance(v) || !get_object(v)) {
1361 jsval_release(v);
1362 return throw_type_error(ctx->script, JS_E_FUNCTION_EXPECTED, NULL);
1365 obj = iface_to_jsdisp((IUnknown*)get_object(v));
1366 IDispatch_Release(get_object(v));
1367 if(!obj) {
1368 FIXME("non-jsdisp objects not supported\n");
1369 return E_FAIL;
1372 if(is_class(obj, JSCLASS_FUNCTION)) {
1373 hres = jsdisp_propget_name(obj, prototypeW, &prot);
1374 }else {
1375 hres = throw_type_error(ctx->script, JS_E_FUNCTION_EXPECTED, NULL);
1377 jsdisp_release(obj);
1378 if(FAILED(hres))
1379 return hres;
1381 v = stack_pop(ctx);
1383 if(is_object_instance(prot)) {
1384 if(is_object_instance(v))
1385 tmp = iface_to_jsdisp((IUnknown*)get_object(v));
1386 for(iter = tmp; !ret && iter; iter = iter->prototype) {
1387 hres = disp_cmp(get_object(prot), to_disp(iter), &ret);
1388 if(FAILED(hres))
1389 break;
1392 if(tmp)
1393 jsdisp_release(tmp);
1394 }else {
1395 FIXME("prototype is not an object\n");
1396 hres = E_FAIL;
1399 jsval_release(prot);
1400 jsval_release(v);
1401 if(FAILED(hres))
1402 return hres;
1404 return stack_push(ctx, jsval_bool(ret));
1407 /* ECMA-262 3rd Edition 11.8.7 */
1408 static HRESULT interp_in(exec_ctx_t *ctx)
1410 const WCHAR *str;
1411 jsstr_t *jsstr;
1412 jsval_t obj, v;
1413 DISPID id = 0;
1414 BOOL ret;
1415 HRESULT hres;
1417 TRACE("\n");
1419 obj = stack_pop(ctx);
1420 if(!is_object_instance(obj) || !get_object(obj)) {
1421 jsval_release(obj);
1422 return throw_type_error(ctx->script, JS_E_OBJECT_EXPECTED, NULL);
1425 v = stack_pop(ctx);
1426 hres = to_flat_string(ctx->script, v, &jsstr, &str);
1427 jsval_release(v);
1428 if(FAILED(hres)) {
1429 IDispatch_Release(get_object(obj));
1430 return hres;
1433 hres = disp_get_id(ctx->script, get_object(obj), str, NULL, 0, &id);
1434 IDispatch_Release(get_object(obj));
1435 jsstr_release(jsstr);
1436 if(SUCCEEDED(hres))
1437 ret = TRUE;
1438 else if(hres == DISP_E_UNKNOWNNAME)
1439 ret = FALSE;
1440 else
1441 return hres;
1443 return stack_push(ctx, jsval_bool(ret));
1446 /* ECMA-262 3rd Edition 11.6.1 */
1447 static HRESULT add_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, jsval_t *ret)
1449 jsval_t r, l;
1450 HRESULT hres;
1452 hres = to_primitive(ctx, lval, &l, NO_HINT);
1453 if(FAILED(hres))
1454 return hres;
1456 hres = to_primitive(ctx, rval, &r, NO_HINT);
1457 if(FAILED(hres)) {
1458 jsval_release(l);
1459 return hres;
1462 if(is_string(l) || is_string(r)) {
1463 jsstr_t *lstr, *rstr = NULL;
1465 hres = to_string(ctx, l, &lstr);
1466 if(SUCCEEDED(hres))
1467 hres = to_string(ctx, r, &rstr);
1469 if(SUCCEEDED(hres)) {
1470 jsstr_t *ret_str;
1472 ret_str = jsstr_concat(lstr, rstr);
1473 if(ret_str)
1474 *ret = jsval_string(ret_str);
1475 else
1476 hres = E_OUTOFMEMORY;
1479 jsstr_release(lstr);
1480 if(rstr)
1481 jsstr_release(rstr);
1482 }else {
1483 double nl, nr;
1485 hres = to_number(ctx, l, &nl);
1486 if(SUCCEEDED(hres)) {
1487 hres = to_number(ctx, r, &nr);
1488 if(SUCCEEDED(hres))
1489 *ret = jsval_number(nl+nr);
1493 jsval_release(r);
1494 jsval_release(l);
1495 return hres;
1498 /* ECMA-262 3rd Edition 11.6.1 */
1499 static HRESULT interp_add(exec_ctx_t *ctx)
1501 jsval_t l, r, ret;
1502 HRESULT hres;
1504 r = stack_pop(ctx);
1505 l = stack_pop(ctx);
1507 TRACE("%s + %s\n", debugstr_jsval(l), debugstr_jsval(r));
1509 hres = add_eval(ctx->script, l, r, &ret);
1510 jsval_release(l);
1511 jsval_release(r);
1512 if(FAILED(hres))
1513 return hres;
1515 return stack_push(ctx, ret);
1518 /* ECMA-262 3rd Edition 11.6.2 */
1519 static HRESULT interp_sub(exec_ctx_t *ctx)
1521 double l, r;
1522 HRESULT hres;
1524 TRACE("\n");
1526 hres = stack_pop_number(ctx, &r);
1527 if(FAILED(hres))
1528 return hres;
1530 hres = stack_pop_number(ctx, &l);
1531 if(FAILED(hres))
1532 return hres;
1534 return stack_push(ctx, jsval_number(l-r));
1537 /* ECMA-262 3rd Edition 11.5.1 */
1538 static HRESULT interp_mul(exec_ctx_t *ctx)
1540 double l, r;
1541 HRESULT hres;
1543 TRACE("\n");
1545 hres = stack_pop_number(ctx, &r);
1546 if(FAILED(hres))
1547 return hres;
1549 hres = stack_pop_number(ctx, &l);
1550 if(FAILED(hres))
1551 return hres;
1553 return stack_push(ctx, jsval_number(l*r));
1556 /* ECMA-262 3rd Edition 11.5.2 */
1557 static HRESULT interp_div(exec_ctx_t *ctx)
1559 double l, r;
1560 HRESULT hres;
1562 TRACE("\n");
1564 hres = stack_pop_number(ctx, &r);
1565 if(FAILED(hres))
1566 return hres;
1568 hres = stack_pop_number(ctx, &l);
1569 if(FAILED(hres))
1570 return hres;
1572 return stack_push(ctx, jsval_number(l/r));
1575 /* ECMA-262 3rd Edition 11.5.3 */
1576 static HRESULT interp_mod(exec_ctx_t *ctx)
1578 double l, r;
1579 HRESULT hres;
1581 TRACE("\n");
1583 hres = stack_pop_number(ctx, &r);
1584 if(FAILED(hres))
1585 return hres;
1587 hres = stack_pop_number(ctx, &l);
1588 if(FAILED(hres))
1589 return hres;
1591 return stack_push(ctx, jsval_number(fmod(l, r)));
1594 /* ECMA-262 3rd Edition 11.4.2 */
1595 static HRESULT interp_delete(exec_ctx_t *ctx)
1597 jsval_t objv, namev;
1598 IDispatch *obj;
1599 jsstr_t *name;
1600 BOOL ret;
1601 HRESULT hres;
1603 TRACE("\n");
1605 namev = stack_pop(ctx);
1606 objv = stack_pop(ctx);
1608 hres = to_object(ctx->script, objv, &obj);
1609 jsval_release(objv);
1610 if(FAILED(hres)) {
1611 jsval_release(namev);
1612 return hres;
1615 hres = to_string(ctx->script, namev, &name);
1616 jsval_release(namev);
1617 if(FAILED(hres)) {
1618 IDispatch_Release(obj);
1619 return hres;
1622 hres = disp_delete_name(ctx->script, obj, name, &ret);
1623 IDispatch_Release(obj);
1624 jsstr_release(name);
1625 if(FAILED(hres))
1626 return hres;
1628 return stack_push(ctx, jsval_bool(ret));
1631 /* ECMA-262 3rd Edition 11.4.2 */
1632 static HRESULT interp_delete_ident(exec_ctx_t *ctx)
1634 const BSTR arg = get_op_bstr(ctx, 0);
1635 exprval_t exprval;
1636 BOOL ret;
1637 HRESULT hres;
1639 TRACE("%s\n", debugstr_w(arg));
1641 hres = identifier_eval(ctx->script, arg, &exprval);
1642 if(FAILED(hres))
1643 return hres;
1645 switch(exprval.type) {
1646 case EXPRVAL_IDREF:
1647 hres = disp_delete(exprval.u.idref.disp, exprval.u.idref.id, &ret);
1648 IDispatch_Release(exprval.u.idref.disp);
1649 if(FAILED(hres))
1650 return hres;
1651 break;
1652 case EXPRVAL_INVALID:
1653 ret = TRUE;
1654 break;
1655 default:
1656 FIXME("Unsupported exprval\n");
1657 exprval_release(&exprval);
1658 return E_NOTIMPL;
1662 return stack_push(ctx, jsval_bool(ret));
1665 /* ECMA-262 3rd Edition 11.4.2 */
1666 static HRESULT interp_void(exec_ctx_t *ctx)
1668 TRACE("\n");
1670 stack_popn(ctx, 1);
1671 return stack_push(ctx, jsval_undefined());
1674 /* ECMA-262 3rd Edition 11.4.3 */
1675 static HRESULT typeof_string(jsval_t v, const WCHAR **ret)
1677 switch(jsval_type(v)) {
1678 case JSV_UNDEFINED:
1679 *ret = undefinedW;
1680 break;
1681 case JSV_NULL:
1682 *ret = objectW;
1683 break;
1684 case JSV_OBJECT: {
1685 jsdisp_t *dispex;
1687 if(get_object(v) && (dispex = iface_to_jsdisp((IUnknown*)get_object(v)))) {
1688 *ret = is_class(dispex, JSCLASS_FUNCTION) ? functionW : objectW;
1689 jsdisp_release(dispex);
1690 }else {
1691 *ret = objectW;
1693 break;
1695 case JSV_STRING:
1696 *ret = stringW;
1697 break;
1698 case JSV_NUMBER:
1699 *ret = numberW;
1700 break;
1701 case JSV_BOOL:
1702 *ret = booleanW;
1703 break;
1704 case JSV_VARIANT:
1705 FIXME("unhandled variant %s\n", debugstr_variant(get_variant(v)));
1706 return E_NOTIMPL;
1709 return S_OK;
1712 /* ECMA-262 3rd Edition 11.4.3 */
1713 static HRESULT interp_typeofid(exec_ctx_t *ctx)
1715 const WCHAR *ret;
1716 IDispatch *obj;
1717 jsval_t v;
1718 DISPID id;
1719 HRESULT hres;
1721 TRACE("\n");
1723 obj = stack_pop_objid(ctx, &id);
1724 if(!obj)
1725 return stack_push(ctx, jsval_string(jsstr_undefined()));
1727 hres = disp_propget(ctx->script, obj, id, &v);
1728 IDispatch_Release(obj);
1729 if(FAILED(hres))
1730 return stack_push_string(ctx, unknownW);
1732 hres = typeof_string(v, &ret);
1733 jsval_release(v);
1734 if(FAILED(hres))
1735 return hres;
1737 return stack_push_string(ctx, ret);
1740 /* ECMA-262 3rd Edition 11.4.3 */
1741 static HRESULT interp_typeofident(exec_ctx_t *ctx)
1743 const BSTR arg = get_op_bstr(ctx, 0);
1744 exprval_t exprval;
1745 const WCHAR *ret;
1746 jsval_t v;
1747 HRESULT hres;
1749 TRACE("%s\n", debugstr_w(arg));
1751 hres = identifier_eval(ctx->script, arg, &exprval);
1752 if(FAILED(hres))
1753 return hres;
1755 if(exprval.type == EXPRVAL_INVALID) {
1756 hres = stack_push(ctx, jsval_string(jsstr_undefined()));
1757 exprval_release(&exprval);
1758 return hres;
1761 hres = exprval_to_value(ctx->script, &exprval, &v);
1762 exprval_release(&exprval);
1763 if(FAILED(hres))
1764 return hres;
1766 hres = typeof_string(v, &ret);
1767 jsval_release(v);
1768 if(FAILED(hres))
1769 return hres;
1771 return stack_push_string(ctx, ret);
1774 /* ECMA-262 3rd Edition 11.4.3 */
1775 static HRESULT interp_typeof(exec_ctx_t *ctx)
1777 const WCHAR *ret;
1778 jsval_t v;
1779 HRESULT hres;
1781 TRACE("\n");
1783 v = stack_pop(ctx);
1784 hres = typeof_string(v, &ret);
1785 jsval_release(v);
1786 if(FAILED(hres))
1787 return hres;
1789 return stack_push_string(ctx, ret);
1792 /* ECMA-262 3rd Edition 11.4.7 */
1793 static HRESULT interp_minus(exec_ctx_t *ctx)
1795 double n;
1796 HRESULT hres;
1798 TRACE("\n");
1800 hres = stack_pop_number(ctx, &n);
1801 if(FAILED(hres))
1802 return hres;
1804 return stack_push(ctx, jsval_number(-n));
1807 /* ECMA-262 3rd Edition 11.4.6 */
1808 static HRESULT interp_tonum(exec_ctx_t *ctx)
1810 jsval_t v;
1811 double n;
1812 HRESULT hres;
1814 TRACE("\n");
1816 v = stack_pop(ctx);
1817 hres = to_number(ctx->script, v, &n);
1818 jsval_release(v);
1819 if(FAILED(hres))
1820 return hres;
1822 return stack_push(ctx, jsval_number(n));
1825 /* ECMA-262 3rd Edition 11.3.1 */
1826 static HRESULT interp_postinc(exec_ctx_t *ctx)
1828 const int arg = get_op_int(ctx, 0);
1829 IDispatch *obj;
1830 DISPID id;
1831 jsval_t v;
1832 HRESULT hres;
1834 TRACE("%d\n", arg);
1836 obj = stack_pop_objid(ctx, &id);
1837 if(!obj)
1838 return throw_type_error(ctx->script, JS_E_OBJECT_EXPECTED, NULL);
1840 hres = disp_propget(ctx->script, obj, id, &v);
1841 if(SUCCEEDED(hres)) {
1842 double n;
1844 hres = to_number(ctx->script, v, &n);
1845 if(SUCCEEDED(hres))
1846 hres = disp_propput(ctx->script, obj, id, jsval_number(n+(double)arg));
1847 if(FAILED(hres))
1848 jsval_release(v);
1850 IDispatch_Release(obj);
1851 if(FAILED(hres))
1852 return hres;
1854 return stack_push(ctx, v);
1857 /* ECMA-262 3rd Edition 11.4.4, 11.4.5 */
1858 static HRESULT interp_preinc(exec_ctx_t *ctx)
1860 const int arg = get_op_int(ctx, 0);
1861 IDispatch *obj;
1862 double ret;
1863 DISPID id;
1864 jsval_t v;
1865 HRESULT hres;
1867 TRACE("%d\n", arg);
1869 obj = stack_pop_objid(ctx, &id);
1870 if(!obj)
1871 return throw_type_error(ctx->script, JS_E_OBJECT_EXPECTED, NULL);
1873 hres = disp_propget(ctx->script, obj, id, &v);
1874 if(SUCCEEDED(hres)) {
1875 double n;
1877 hres = to_number(ctx->script, v, &n);
1878 jsval_release(v);
1879 if(SUCCEEDED(hres)) {
1880 ret = n+(double)arg;
1881 hres = disp_propput(ctx->script, obj, id, jsval_number(ret));
1884 IDispatch_Release(obj);
1885 if(FAILED(hres))
1886 return hres;
1888 return stack_push(ctx, jsval_number(ret));
1891 /* ECMA-262 3rd Edition 11.9.3 */
1892 static HRESULT equal_values(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL *ret)
1894 if(jsval_type(lval) == jsval_type(rval) || (is_number(lval) && is_number(rval)))
1895 return equal2_values(lval, rval, ret);
1897 /* FIXME: NULL disps should be handled in more general way */
1898 if(is_object_instance(lval) && !get_object(lval))
1899 return equal_values(ctx, jsval_null(), rval, ret);
1900 if(is_object_instance(rval) && !get_object(rval))
1901 return equal_values(ctx, lval, jsval_null(), ret);
1903 if((is_null(lval) && is_undefined(rval)) || (is_undefined(lval) && is_null(rval))) {
1904 *ret = TRUE;
1905 return S_OK;
1908 if(is_string(lval) && is_number(rval)) {
1909 double n;
1910 HRESULT hres;
1912 hres = to_number(ctx, lval, &n);
1913 if(FAILED(hres))
1914 return hres;
1916 /* FIXME: optimize */
1917 return equal_values(ctx, jsval_number(n), rval, ret);
1920 if(is_string(rval) && is_number(lval)) {
1921 double n;
1922 HRESULT hres;
1924 hres = to_number(ctx, rval, &n);
1925 if(FAILED(hres))
1926 return hres;
1928 /* FIXME: optimize */
1929 return equal_values(ctx, lval, jsval_number(n), ret);
1932 if(is_bool(rval))
1933 return equal_values(ctx, lval, jsval_number(get_bool(rval) ? 1 : 0), ret);
1935 if(is_bool(lval))
1936 return equal_values(ctx, jsval_number(get_bool(lval) ? 1 : 0), rval, ret);
1939 if(is_object_instance(rval) && (is_string(lval) || is_number(lval))) {
1940 jsval_t prim;
1941 HRESULT hres;
1943 hres = to_primitive(ctx, rval, &prim, NO_HINT);
1944 if(FAILED(hres))
1945 return hres;
1947 hres = equal_values(ctx, lval, prim, ret);
1948 jsval_release(prim);
1949 return hres;
1953 if(is_object_instance(lval) && (is_string(rval) || is_number(rval))) {
1954 jsval_t prim;
1955 HRESULT hres;
1957 hres = to_primitive(ctx, lval, &prim, NO_HINT);
1958 if(FAILED(hres))
1959 return hres;
1961 hres = equal_values(ctx, prim, rval, ret);
1962 jsval_release(prim);
1963 return hres;
1967 *ret = FALSE;
1968 return S_OK;
1971 /* ECMA-262 3rd Edition 11.9.1 */
1972 static HRESULT interp_eq(exec_ctx_t *ctx)
1974 jsval_t l, r;
1975 BOOL b;
1976 HRESULT hres;
1978 r = stack_pop(ctx);
1979 l = stack_pop(ctx);
1981 TRACE("%s == %s\n", debugstr_jsval(l), debugstr_jsval(r));
1983 hres = equal_values(ctx->script, l, r, &b);
1984 jsval_release(l);
1985 jsval_release(r);
1986 if(FAILED(hres))
1987 return hres;
1989 return stack_push(ctx, jsval_bool(b));
1992 /* ECMA-262 3rd Edition 11.9.2 */
1993 static HRESULT interp_neq(exec_ctx_t *ctx)
1995 jsval_t l, r;
1996 BOOL b;
1997 HRESULT hres;
1999 r = stack_pop(ctx);
2000 l = stack_pop(ctx);
2002 TRACE("%s != %s\n", debugstr_jsval(l), debugstr_jsval(r));
2004 hres = equal_values(ctx->script, l, r, &b);
2005 jsval_release(l);
2006 jsval_release(r);
2007 if(FAILED(hres))
2008 return hres;
2010 return stack_push(ctx, jsval_bool(!b));
2013 /* ECMA-262 3rd Edition 11.9.4 */
2014 static HRESULT interp_eq2(exec_ctx_t *ctx)
2016 jsval_t l, r;
2017 BOOL b;
2018 HRESULT hres;
2020 r = stack_pop(ctx);
2021 l = stack_pop(ctx);
2023 TRACE("%s === %s\n", debugstr_jsval(l), debugstr_jsval(r));
2025 hres = equal2_values(r, l, &b);
2026 jsval_release(l);
2027 jsval_release(r);
2028 if(FAILED(hres))
2029 return hres;
2031 return stack_push(ctx, jsval_bool(b));
2034 /* ECMA-262 3rd Edition 11.9.5 */
2035 static HRESULT interp_neq2(exec_ctx_t *ctx)
2037 jsval_t l, r;
2038 BOOL b;
2039 HRESULT hres;
2041 TRACE("\n");
2043 r = stack_pop(ctx);
2044 l = stack_pop(ctx);
2046 hres = equal2_values(r, l, &b);
2047 jsval_release(l);
2048 jsval_release(r);
2049 if(FAILED(hres))
2050 return hres;
2052 return stack_push(ctx, jsval_bool(!b));
2055 /* ECMA-262 3rd Edition 11.8.5 */
2056 static HRESULT less_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL greater, BOOL *ret)
2058 double ln, rn;
2059 jsval_t l, r;
2060 HRESULT hres;
2062 hres = to_primitive(ctx, lval, &l, NO_HINT);
2063 if(FAILED(hres))
2064 return hres;
2066 hres = to_primitive(ctx, rval, &r, NO_HINT);
2067 if(FAILED(hres)) {
2068 jsval_release(l);
2069 return hres;
2072 if(is_string(l) && is_string(r)) {
2073 *ret = (jsstr_cmp(get_string(l), get_string(r)) < 0) ^ greater;
2074 jsstr_release(get_string(l));
2075 jsstr_release(get_string(r));
2076 return S_OK;
2079 hres = to_number(ctx, l, &ln);
2080 jsval_release(l);
2081 if(SUCCEEDED(hres))
2082 hres = to_number(ctx, r, &rn);
2083 jsval_release(r);
2084 if(FAILED(hres))
2085 return hres;
2087 *ret = !isnan(ln) && !isnan(rn) && ((ln < rn) ^ greater);
2088 return S_OK;
2091 /* ECMA-262 3rd Edition 11.8.1 */
2092 static HRESULT interp_lt(exec_ctx_t *ctx)
2094 jsval_t l, r;
2095 BOOL b;
2096 HRESULT hres;
2098 r = stack_pop(ctx);
2099 l = stack_pop(ctx);
2101 TRACE("%s < %s\n", debugstr_jsval(l), debugstr_jsval(r));
2103 hres = less_eval(ctx->script, l, r, FALSE, &b);
2104 jsval_release(l);
2105 jsval_release(r);
2106 if(FAILED(hres))
2107 return hres;
2109 return stack_push(ctx, jsval_bool(b));
2112 /* ECMA-262 3rd Edition 11.8.1 */
2113 static HRESULT interp_lteq(exec_ctx_t *ctx)
2115 jsval_t l, r;
2116 BOOL b;
2117 HRESULT hres;
2119 r = stack_pop(ctx);
2120 l = stack_pop(ctx);
2122 TRACE("%s <= %s\n", debugstr_jsval(l), debugstr_jsval(r));
2124 hres = less_eval(ctx->script, r, l, TRUE, &b);
2125 jsval_release(l);
2126 jsval_release(r);
2127 if(FAILED(hres))
2128 return hres;
2130 return stack_push(ctx, jsval_bool(b));
2133 /* ECMA-262 3rd Edition 11.8.2 */
2134 static HRESULT interp_gt(exec_ctx_t *ctx)
2136 jsval_t l, r;
2137 BOOL b;
2138 HRESULT hres;
2140 r = stack_pop(ctx);
2141 l = stack_pop(ctx);
2143 TRACE("%s > %s\n", debugstr_jsval(l), debugstr_jsval(r));
2145 hres = less_eval(ctx->script, r, l, FALSE, &b);
2146 jsval_release(l);
2147 jsval_release(r);
2148 if(FAILED(hres))
2149 return hres;
2151 return stack_push(ctx, jsval_bool(b));
2154 /* ECMA-262 3rd Edition 11.8.4 */
2155 static HRESULT interp_gteq(exec_ctx_t *ctx)
2157 jsval_t l, r;
2158 BOOL b;
2159 HRESULT hres;
2161 r = stack_pop(ctx);
2162 l = stack_pop(ctx);
2164 TRACE("%s >= %s\n", debugstr_jsval(l), debugstr_jsval(r));
2166 hres = less_eval(ctx->script, l, r, TRUE, &b);
2167 jsval_release(l);
2168 jsval_release(r);
2169 if(FAILED(hres))
2170 return hres;
2172 return stack_push(ctx, jsval_bool(b));
2175 /* ECMA-262 3rd Edition 11.4.8 */
2176 static HRESULT interp_bneg(exec_ctx_t *ctx)
2178 jsval_t v;
2179 INT i;
2180 HRESULT hres;
2182 TRACE("\n");
2184 v = stack_pop(ctx);
2185 hres = to_int32(ctx->script, v, &i);
2186 jsval_release(v);
2187 if(FAILED(hres))
2188 return hres;
2190 return stack_push(ctx, jsval_number(~i));
2193 /* ECMA-262 3rd Edition 11.4.9 */
2194 static HRESULT interp_neg(exec_ctx_t *ctx)
2196 jsval_t v;
2197 BOOL b;
2198 HRESULT hres;
2200 TRACE("\n");
2202 v = stack_pop(ctx);
2203 hres = to_boolean(v, &b);
2204 jsval_release(v);
2205 if(FAILED(hres))
2206 return hres;
2208 return stack_push(ctx, jsval_bool(!b));
2211 /* ECMA-262 3rd Edition 11.7.1 */
2212 static HRESULT interp_lshift(exec_ctx_t *ctx)
2214 DWORD r;
2215 INT l;
2216 HRESULT hres;
2218 hres = stack_pop_uint(ctx, &r);
2219 if(FAILED(hres))
2220 return hres;
2222 hres = stack_pop_int(ctx, &l);
2223 if(FAILED(hres))
2224 return hres;
2226 return stack_push(ctx, jsval_number(l << (r&0x1f)));
2229 /* ECMA-262 3rd Edition 11.7.2 */
2230 static HRESULT interp_rshift(exec_ctx_t *ctx)
2232 DWORD r;
2233 INT l;
2234 HRESULT hres;
2236 hres = stack_pop_uint(ctx, &r);
2237 if(FAILED(hres))
2238 return hres;
2240 hres = stack_pop_int(ctx, &l);
2241 if(FAILED(hres))
2242 return hres;
2244 return stack_push(ctx, jsval_number(l >> (r&0x1f)));
2247 /* ECMA-262 3rd Edition 11.7.3 */
2248 static HRESULT interp_rshift2(exec_ctx_t *ctx)
2250 DWORD r, l;
2251 HRESULT hres;
2253 hres = stack_pop_uint(ctx, &r);
2254 if(FAILED(hres))
2255 return hres;
2257 hres = stack_pop_uint(ctx, &l);
2258 if(FAILED(hres))
2259 return hres;
2261 return stack_push(ctx, jsval_number(l >> (r&0x1f)));
2264 /* ECMA-262 3rd Edition 11.13.1 */
2265 static HRESULT interp_assign(exec_ctx_t *ctx)
2267 IDispatch *disp;
2268 DISPID id;
2269 jsval_t v;
2270 HRESULT hres;
2272 TRACE("\n");
2274 v = stack_pop(ctx);
2276 disp = stack_pop_objid(ctx, &id);
2277 if(!disp) {
2278 jsval_release(v);
2279 return throw_reference_error(ctx->script, JS_E_ILLEGAL_ASSIGN, NULL);
2282 hres = disp_propput(ctx->script, disp, id, v);
2283 IDispatch_Release(disp);
2284 if(FAILED(hres)) {
2285 jsval_release(v);
2286 return hres;
2289 return stack_push(ctx, v);
2292 /* JScript extension */
2293 static HRESULT interp_assign_call(exec_ctx_t *ctx)
2295 const unsigned argc = get_op_uint(ctx, 0);
2296 IDispatch *disp;
2297 jsval_t v;
2298 DISPID id;
2299 HRESULT hres;
2301 TRACE("%u\n", argc);
2303 disp = stack_topn_objid(ctx, argc+1, &id);
2304 if(!disp)
2305 return throw_reference_error(ctx->script, JS_E_ILLEGAL_ASSIGN, NULL);
2307 hres = disp_call(ctx->script, disp, id, DISPATCH_PROPERTYPUT, argc+1, stack_args(ctx, argc+1), NULL);
2308 if(FAILED(hres))
2309 return hres;
2311 v = stack_pop(ctx);
2312 stack_popn(ctx, argc+2);
2313 return stack_push(ctx, v);
2316 static HRESULT interp_undefined(exec_ctx_t *ctx)
2318 TRACE("\n");
2320 return stack_push(ctx, jsval_undefined());
2323 static HRESULT interp_jmp(exec_ctx_t *ctx)
2325 const unsigned arg = get_op_uint(ctx, 0);
2327 TRACE("%u\n", arg);
2329 ctx->ip = arg;
2330 return S_OK;
2333 static HRESULT interp_jmp_z(exec_ctx_t *ctx)
2335 const unsigned arg = get_op_uint(ctx, 0);
2336 BOOL b;
2337 jsval_t v;
2338 HRESULT hres;
2340 TRACE("\n");
2342 v = stack_pop(ctx);
2343 hres = to_boolean(v, &b);
2344 jsval_release(v);
2345 if(FAILED(hres))
2346 return hres;
2348 if(b)
2349 ctx->ip++;
2350 else
2351 ctx->ip = arg;
2352 return S_OK;
2355 static HRESULT interp_pop(exec_ctx_t *ctx)
2357 const unsigned arg = get_op_uint(ctx, 0);
2359 TRACE("%u\n", arg);
2361 stack_popn(ctx, arg);
2362 return S_OK;
2365 static HRESULT interp_ret(exec_ctx_t *ctx)
2367 TRACE("\n");
2369 ctx->ip = -1;
2370 return S_OK;
2373 static HRESULT interp_setret(exec_ctx_t *ctx)
2375 TRACE("\n");
2377 jsval_release(ctx->ret);
2378 ctx->ret = stack_pop(ctx);
2379 return S_OK;
2382 typedef HRESULT (*op_func_t)(exec_ctx_t*);
2384 static const op_func_t op_funcs[] = {
2385 #define X(x,a,b,c) interp_##x,
2386 OP_LIST
2387 #undef X
2390 static const unsigned op_move[] = {
2391 #define X(a,x,b,c) x,
2392 OP_LIST
2393 #undef X
2396 static HRESULT unwind_exception(exec_ctx_t *ctx)
2398 except_frame_t *except_frame;
2399 jsval_t except_val;
2400 BSTR ident;
2401 HRESULT hres;
2403 except_frame = ctx->except_frame;
2404 ctx->except_frame = except_frame->next;
2406 assert(except_frame->stack_top <= ctx->top);
2407 stack_popn(ctx, ctx->top - except_frame->stack_top);
2409 while(except_frame->scope != ctx->scope_chain)
2410 scope_pop(&ctx->scope_chain);
2412 ctx->ip = except_frame->catch_off;
2414 except_val = ctx->script->ei.val;
2415 ctx->script->ei.val = jsval_undefined();
2416 clear_ei(ctx->script);
2418 ident = except_frame->ident;
2419 heap_free(except_frame);
2421 if(ident) {
2422 jsdisp_t *scope_obj;
2424 hres = create_dispex(ctx->script, NULL, NULL, &scope_obj);
2425 if(SUCCEEDED(hres)) {
2426 hres = jsdisp_propput_name(scope_obj, ident, except_val);
2427 if(FAILED(hres))
2428 jsdisp_release(scope_obj);
2430 jsval_release(except_val);
2431 if(FAILED(hres))
2432 return hres;
2434 hres = scope_push(ctx->scope_chain, scope_obj, to_disp(scope_obj), &ctx->scope_chain);
2435 jsdisp_release(scope_obj);
2436 }else {
2437 hres = stack_push(ctx, except_val);
2438 if(FAILED(hres))
2439 return hres;
2441 hres = stack_push(ctx, jsval_bool(FALSE));
2444 return hres;
2447 static HRESULT enter_bytecode(script_ctx_t *ctx, bytecode_t *code, function_code_t *func, jsval_t *ret)
2449 exec_ctx_t *exec_ctx = ctx->exec_ctx;
2450 except_frame_t *prev_except_frame;
2451 function_code_t *prev_func;
2452 unsigned prev_ip, prev_top;
2453 scope_chain_t *prev_scope;
2454 bytecode_t *prev_code;
2455 jsop_t op;
2456 HRESULT hres = S_OK;
2458 TRACE("\n");
2460 prev_top = exec_ctx->top;
2461 prev_scope = exec_ctx->scope_chain;
2462 prev_except_frame = exec_ctx->except_frame;
2463 prev_ip = exec_ctx->ip;
2464 prev_code = exec_ctx->code;
2465 prev_func = exec_ctx->func_code;
2466 exec_ctx->ip = func->instr_off;
2467 exec_ctx->except_frame = NULL;
2468 exec_ctx->code = code;
2469 exec_ctx->func_code = func;
2471 while(exec_ctx->ip != -1) {
2472 op = code->instrs[exec_ctx->ip].op;
2473 hres = op_funcs[op](exec_ctx);
2474 if(FAILED(hres)) {
2475 TRACE("EXCEPTION %08x\n", hres);
2477 if(!exec_ctx->except_frame)
2478 break;
2480 hres = unwind_exception(exec_ctx);
2481 if(FAILED(hres))
2482 break;
2483 }else {
2484 exec_ctx->ip += op_move[op];
2488 exec_ctx->ip = prev_ip;
2489 exec_ctx->except_frame = prev_except_frame;
2490 exec_ctx->code = prev_code;
2491 exec_ctx->func_code = prev_func;
2493 if(FAILED(hres)) {
2494 while(exec_ctx->scope_chain != prev_scope)
2495 scope_pop(&exec_ctx->scope_chain);
2496 stack_popn(exec_ctx, exec_ctx->top-prev_top);
2497 return hres;
2500 assert(exec_ctx->top == prev_top+1 || exec_ctx->top == prev_top);
2501 assert(exec_ctx->scope_chain == prev_scope);
2502 assert(exec_ctx->top == prev_top);
2504 *ret = exec_ctx->ret;
2505 exec_ctx->ret = jsval_undefined();
2506 return S_OK;
2509 static HRESULT bind_event_target(script_ctx_t *ctx, function_code_t *func, jsdisp_t *func_obj)
2511 IBindEventHandler *target;
2512 exprval_t exprval;
2513 IDispatch *disp;
2514 jsval_t v;
2515 HRESULT hres;
2517 hres = identifier_eval(ctx, func->event_target, &exprval);
2518 if(FAILED(hres))
2519 return hres;
2521 hres = exprval_to_value(ctx, &exprval, &v);
2522 exprval_release(&exprval);
2523 if(FAILED(hres))
2524 return hres;
2526 if(!is_object_instance(v)) {
2527 FIXME("Can't bind to %s\n", debugstr_jsval(v));
2528 jsval_release(v);
2531 disp = get_object(v);
2532 hres = IDispatch_QueryInterface(disp, &IID_IBindEventHandler, (void**)&target);
2533 if(SUCCEEDED(hres)) {
2534 hres = IBindEventHandler_BindHandler(target, func->name, (IDispatch*)&func_obj->IDispatchEx_iface);
2535 IBindEventHandler_Release(target);
2536 if(FAILED(hres))
2537 WARN("BindEvent failed: %08x\n", hres);
2538 }else {
2539 FIXME("No IBindEventHandler, not yet supported binding\n");
2542 IDispatch_Release(disp);
2543 return hres;
2546 HRESULT exec_source(exec_ctx_t *ctx, bytecode_t *code, function_code_t *func, BOOL from_eval, jsval_t *ret)
2548 exec_ctx_t *prev_ctx;
2549 jsval_t val;
2550 unsigned i;
2551 HRESULT hres = S_OK;
2553 for(i = 0; i < func->func_cnt; i++) {
2554 jsdisp_t *func_obj;
2556 if(!func->funcs[i].name)
2557 continue;
2559 hres = create_source_function(ctx->script, code, func->funcs+i, ctx->scope_chain, &func_obj);
2560 if(FAILED(hres))
2561 return hres;
2563 if(func->funcs[i].event_target)
2564 hres = bind_event_target(ctx->script, func->funcs+i, func_obj);
2565 else
2566 hres = jsdisp_propput_name(ctx->var_disp, func->funcs[i].name, jsval_obj(func_obj));
2567 jsdisp_release(func_obj);
2568 if(FAILED(hres))
2569 return hres;
2572 for(i=0; i < func->var_cnt; i++) {
2573 if(!ctx->is_global || !lookup_global_members(ctx->script, func->variables[i], NULL)) {
2574 DISPID id = 0;
2576 hres = jsdisp_get_id(ctx->var_disp, func->variables[i], fdexNameEnsure, &id);
2577 if(FAILED(hres))
2578 return hres;
2582 prev_ctx = ctx->script->exec_ctx;
2583 ctx->script->exec_ctx = ctx;
2585 hres = enter_bytecode(ctx->script, code, func, &val);
2586 assert(ctx->script->exec_ctx == ctx);
2587 ctx->script->exec_ctx = prev_ctx;
2588 if(FAILED(hres))
2589 return hres;
2591 if(ret)
2592 *ret = val;
2593 else
2594 jsval_release(val);
2595 return S_OK;