jscript: Store return value in call_frame_t.
[wine.git] / dlls / jscript / engine.c
blob0a46b58d21cca8564b21cca23ec0a584c2b33bc7
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(script_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->stack_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->stack_top++] = v;
85 return S_OK;
88 static inline HRESULT stack_push_string(script_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(script_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(script_ctx_t *ctx)
112 assert(ctx->stack_top > ctx->call_ctx->stack_base);
113 return ctx->stack[ctx->stack_top-1];
116 static inline jsval_t stack_topn(script_ctx_t *ctx, unsigned n)
118 assert(ctx->stack_top > ctx->call_ctx->stack_base+n);
119 return ctx->stack[ctx->stack_top-1-n];
122 static inline jsval_t *stack_args(script_ctx_t *ctx, unsigned n)
124 if(!n)
125 return NULL;
126 assert(ctx->stack_top > ctx->call_ctx->stack_base+n-1);
127 return ctx->stack + ctx->stack_top-n;
130 static inline jsval_t stack_pop(script_ctx_t *ctx)
132 assert(ctx->stack_top > ctx->call_ctx->stack_base);
133 return ctx->stack[--ctx->stack_top];
136 static void stack_popn(script_ctx_t *ctx, unsigned n)
138 while(n--)
139 jsval_release(stack_pop(ctx));
142 static HRESULT stack_pop_number(script_ctx_t *ctx, double *r)
144 jsval_t v;
145 HRESULT hres;
147 v = stack_pop(ctx);
148 hres = to_number(ctx, v, r);
149 jsval_release(v);
150 return hres;
153 static HRESULT stack_pop_object(script_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, JS_E_OBJECT_REQUIRED, NULL);
162 *r = get_object(v);
163 return S_OK;
166 hres = to_object(ctx, v, r);
167 jsval_release(v);
168 return hres;
171 static inline HRESULT stack_pop_int(script_ctx_t *ctx, INT *r)
173 return to_int32(ctx, stack_pop(ctx), r);
176 static inline HRESULT stack_pop_uint(script_ctx_t *ctx, DWORD *r)
178 return to_uint32(ctx, stack_pop(ctx), r);
181 static inline IDispatch *stack_pop_objid(script_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(script_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, BOOL is_global, exec_ctx_t **ret)
300 exec_ctx_t *ctx;
302 ctx = heap_alloc_zero(sizeof(exec_ctx_t));
303 if(!ctx)
304 return E_OUTOFMEMORY;
306 ctx->ref = 1;
307 ctx->is_global = is_global;
309 script_addref(script_ctx);
310 ctx->script = script_ctx;
312 *ret = ctx;
313 return S_OK;
316 void exec_release(exec_ctx_t *ctx)
318 if(--ctx->ref)
319 return;
321 if(ctx->script)
322 script_release(ctx->script);
323 heap_free(ctx);
326 static HRESULT disp_get_id(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name, BSTR name_bstr, DWORD flags, DISPID *id)
328 IDispatchEx *dispex;
329 jsdisp_t *jsdisp;
330 BSTR bstr;
331 HRESULT hres;
333 jsdisp = iface_to_jsdisp((IUnknown*)disp);
334 if(jsdisp) {
335 hres = jsdisp_get_id(jsdisp, name, flags, id);
336 jsdisp_release(jsdisp);
337 return hres;
340 if(name_bstr) {
341 bstr = name_bstr;
342 }else {
343 bstr = SysAllocString(name);
344 if(!bstr)
345 return E_OUTOFMEMORY;
348 *id = 0;
349 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
350 if(SUCCEEDED(hres)) {
351 hres = IDispatchEx_GetDispID(dispex, bstr, make_grfdex(ctx, flags|fdexNameCaseSensitive), id);
352 IDispatchEx_Release(dispex);
353 }else {
354 TRACE("using IDispatch\n");
355 hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, id);
358 if(name_bstr != bstr)
359 SysFreeString(bstr);
360 return hres;
363 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, BOOL *ret)
365 IObjectIdentity *identity;
366 IUnknown *unk1, *unk2;
367 HRESULT hres;
369 if(disp1 == disp2) {
370 *ret = TRUE;
371 return S_OK;
374 if(!disp1 || !disp2) {
375 *ret = FALSE;
376 return S_OK;
379 hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
380 if(FAILED(hres))
381 return hres;
383 hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
384 if(FAILED(hres)) {
385 IUnknown_Release(unk1);
386 return hres;
389 if(unk1 == unk2) {
390 *ret = TRUE;
391 }else {
392 hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
393 if(SUCCEEDED(hres)) {
394 hres = IObjectIdentity_IsEqualObject(identity, unk2);
395 IObjectIdentity_Release(identity);
396 *ret = hres == S_OK;
397 }else {
398 *ret = FALSE;
402 IUnknown_Release(unk1);
403 IUnknown_Release(unk2);
404 return S_OK;
407 /* ECMA-262 3rd Edition 11.9.6 */
408 static HRESULT equal2_values(jsval_t lval, jsval_t rval, BOOL *ret)
410 jsval_type_t type = jsval_type(lval);
412 TRACE("\n");
414 if(type != jsval_type(rval)) {
415 if(is_null_instance(lval))
416 *ret = is_null_instance(rval);
417 else
418 *ret = FALSE;
419 return S_OK;
422 switch(type) {
423 case JSV_UNDEFINED:
424 case JSV_NULL:
425 *ret = TRUE;
426 break;
427 case JSV_OBJECT:
428 return disp_cmp(get_object(lval), get_object(rval), ret);
429 case JSV_STRING:
430 *ret = jsstr_eq(get_string(lval), get_string(rval));
431 break;
432 case JSV_NUMBER:
433 *ret = get_number(lval) == get_number(rval);
434 break;
435 case JSV_BOOL:
436 *ret = !get_bool(lval) == !get_bool(rval);
437 break;
438 case JSV_VARIANT:
439 FIXME("VARIANT not implemented\n");
440 return E_NOTIMPL;
443 return S_OK;
446 static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
448 named_item_t *item;
449 DISPID id;
450 HRESULT hres;
452 for(item = ctx->named_items; item; item = item->next) {
453 if(item->flags & SCRIPTITEM_GLOBALMEMBERS) {
454 hres = disp_get_id(ctx, item->disp, identifier, identifier, 0, &id);
455 if(SUCCEEDED(hres)) {
456 if(ret)
457 exprval_set_idref(ret, item->disp, id);
458 return TRUE;
463 return FALSE;
466 /* ECMA-262 3rd Edition 10.1.4 */
467 static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
469 scope_chain_t *scope;
470 named_item_t *item;
471 DISPID id = 0;
472 HRESULT hres;
474 TRACE("%s\n", debugstr_w(identifier));
476 if(ctx->call_ctx) {
477 for(scope = ctx->call_ctx->scope; scope; scope = scope->next) {
478 if(scope->jsobj)
479 hres = jsdisp_get_id(scope->jsobj, identifier, fdexNameImplicit, &id);
480 else
481 hres = disp_get_id(ctx, scope->obj, identifier, identifier, fdexNameImplicit, &id);
482 if(SUCCEEDED(hres)) {
483 exprval_set_idref(ret, scope->obj, id);
484 return S_OK;
489 hres = jsdisp_get_id(ctx->global, identifier, 0, &id);
490 if(SUCCEEDED(hres)) {
491 exprval_set_idref(ret, to_disp(ctx->global), id);
492 return S_OK;
495 for(item = ctx->named_items; item; item = item->next) {
496 if((item->flags & SCRIPTITEM_ISVISIBLE) && !strcmpW(item->name, identifier)) {
497 if(!item->disp) {
498 IUnknown *unk;
500 if(!ctx->site)
501 break;
503 hres = IActiveScriptSite_GetItemInfo(ctx->site, identifier,
504 SCRIPTINFO_IUNKNOWN, &unk, NULL);
505 if(FAILED(hres)) {
506 WARN("GetItemInfo failed: %08x\n", hres);
507 break;
510 hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp);
511 IUnknown_Release(unk);
512 if(FAILED(hres)) {
513 WARN("object does not implement IDispatch\n");
514 break;
518 IDispatch_AddRef(item->disp);
519 ret->type = EXPRVAL_JSVAL;
520 ret->u.val = jsval_disp(item->disp);
521 return S_OK;
525 if(lookup_global_members(ctx, identifier, ret))
526 return S_OK;
528 ret->type = EXPRVAL_INVALID;
529 return S_OK;
532 static inline BSTR get_op_bstr(script_ctx_t *ctx, int i)
534 call_frame_t *frame = ctx->call_ctx;
535 return frame->bytecode->instrs[frame->ip].u.arg[i].bstr;
538 static inline unsigned get_op_uint(script_ctx_t *ctx, int i)
540 call_frame_t *frame = ctx->call_ctx;
541 return frame->bytecode->instrs[frame->ip].u.arg[i].uint;
544 static inline unsigned get_op_int(script_ctx_t *ctx, int i)
546 call_frame_t *frame = ctx->call_ctx;
547 return frame->bytecode->instrs[frame->ip].u.arg[i].lng;
550 static inline jsstr_t *get_op_str(script_ctx_t *ctx, int i)
552 call_frame_t *frame = ctx->call_ctx;
553 return frame->bytecode->instrs[frame->ip].u.arg[i].str;
556 static inline double get_op_double(script_ctx_t *ctx)
558 call_frame_t *frame = ctx->call_ctx;
559 return frame->bytecode->instrs[frame->ip].u.dbl;
562 static inline void jmp_next(script_ctx_t *ctx)
564 ctx->call_ctx->ip++;
567 static inline void jmp_abs(script_ctx_t *ctx, unsigned dst)
569 ctx->call_ctx->ip = dst;
572 /* ECMA-262 3rd Edition 12.2 */
573 static HRESULT interp_var_set(script_ctx_t *ctx)
575 const BSTR name = get_op_bstr(ctx, 0);
576 jsval_t val;
577 HRESULT hres;
579 TRACE("%s\n", debugstr_w(name));
581 val = stack_pop(ctx);
582 hres = jsdisp_propput_name(ctx->call_ctx->variable_obj, name, val);
583 jsval_release(val);
584 return hres;
587 /* ECMA-262 3rd Edition 12.6.4 */
588 static HRESULT interp_forin(script_ctx_t *ctx)
590 const HRESULT arg = get_op_uint(ctx, 0);
591 IDispatch *var_obj, *obj = NULL;
592 IDispatchEx *dispex;
593 DISPID id, var_id;
594 BSTR name = NULL;
595 HRESULT hres;
597 TRACE("\n");
599 assert(is_number(stack_top(ctx)));
600 id = get_number(stack_top(ctx));
602 var_obj = stack_topn_objid(ctx, 1, &var_id);
603 if(!var_obj) {
604 FIXME("invalid ref\n");
605 return E_FAIL;
608 if(is_object_instance(stack_topn(ctx, 3)))
609 obj = get_object(stack_topn(ctx, 3));
611 if(obj) {
612 hres = IDispatch_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
613 if(SUCCEEDED(hres)) {
614 hres = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, id, &id);
615 if(hres == S_OK)
616 hres = IDispatchEx_GetMemberName(dispex, id, &name);
617 IDispatchEx_Release(dispex);
618 if(FAILED(hres))
619 return hres;
620 }else {
621 TRACE("No IDispatchEx\n");
625 if(name) {
626 jsstr_t *str;
628 str = jsstr_alloc_len(name, SysStringLen(name));
629 SysFreeString(name);
630 if(!str)
631 return E_OUTOFMEMORY;
633 stack_pop(ctx);
634 stack_push(ctx, jsval_number(id)); /* safe, just after pop() */
636 hres = disp_propput(ctx, var_obj, var_id, jsval_string(str));
637 jsstr_release(str);
638 if(FAILED(hres))
639 return hres;
641 jmp_next(ctx);
642 }else {
643 stack_popn(ctx, 4);
644 jmp_abs(ctx, arg);
646 return S_OK;
649 /* ECMA-262 3rd Edition 12.10 */
650 static HRESULT interp_push_scope(script_ctx_t *ctx)
652 IDispatch *disp;
653 jsval_t v;
654 HRESULT hres;
656 TRACE("\n");
658 v = stack_pop(ctx);
659 hres = to_object(ctx, v, &disp);
660 jsval_release(v);
661 if(FAILED(hres))
662 return hres;
664 hres = scope_push(ctx->call_ctx->scope, to_jsdisp(disp), disp, &ctx->call_ctx->scope);
665 IDispatch_Release(disp);
666 return hres;
669 /* ECMA-262 3rd Edition 12.10 */
670 static HRESULT interp_pop_scope(script_ctx_t *ctx)
672 TRACE("\n");
674 scope_pop(&ctx->call_ctx->scope);
675 return S_OK;
678 /* ECMA-262 3rd Edition 12.13 */
679 static HRESULT interp_case(script_ctx_t *ctx)
681 const unsigned arg = get_op_uint(ctx, 0);
682 jsval_t v;
683 BOOL b;
684 HRESULT hres;
686 TRACE("\n");
688 v = stack_pop(ctx);
689 hres = equal2_values(stack_top(ctx), v, &b);
690 jsval_release(v);
691 if(FAILED(hres))
692 return hres;
694 if(b) {
695 stack_popn(ctx, 1);
696 jmp_abs(ctx, arg);
697 }else {
698 jmp_next(ctx);
700 return S_OK;
703 /* ECMA-262 3rd Edition 12.13 */
704 static HRESULT interp_throw(script_ctx_t *ctx)
706 TRACE("\n");
708 jsval_release(ctx->ei.val);
709 ctx->ei.val = stack_pop(ctx);
710 return DISP_E_EXCEPTION;
713 static HRESULT interp_throw_ref(script_ctx_t *ctx)
715 const HRESULT arg = get_op_uint(ctx, 0);
717 TRACE("%08x\n", arg);
719 return throw_reference_error(ctx, arg, NULL);
722 static HRESULT interp_throw_type(script_ctx_t *ctx)
724 const HRESULT hres = get_op_uint(ctx, 0);
725 jsstr_t *str = get_op_str(ctx, 1);
726 const WCHAR *ptr;
728 TRACE("%08x %s\n", hres, debugstr_jsstr(str));
730 ptr = jsstr_flatten(str);
731 return ptr ? throw_type_error(ctx, hres, ptr) : E_OUTOFMEMORY;
734 /* ECMA-262 3rd Edition 12.14 */
735 static HRESULT interp_push_except(script_ctx_t *ctx)
737 const unsigned arg1 = get_op_uint(ctx, 0);
738 const BSTR arg2 = get_op_bstr(ctx, 1);
739 call_frame_t *frame = ctx->call_ctx;
740 except_frame_t *except;
741 unsigned stack_top;
743 TRACE("\n");
745 stack_top = ctx->stack_top;
747 if(!arg2) {
748 HRESULT hres;
750 hres = stack_push(ctx, jsval_bool(TRUE));
751 if(FAILED(hres))
752 return hres;
753 hres = stack_push(ctx, jsval_bool(TRUE));
754 if(FAILED(hres))
755 return hres;
758 except = heap_alloc(sizeof(*except));
759 if(!except)
760 return E_OUTOFMEMORY;
762 except->stack_top = stack_top;
763 except->scope = frame->scope;
764 except->catch_off = arg1;
765 except->ident = arg2;
766 except->next = frame->except_frame;
767 frame->except_frame = except;
768 return S_OK;
771 /* ECMA-262 3rd Edition 12.14 */
772 static HRESULT interp_pop_except(script_ctx_t *ctx)
774 call_frame_t *frame = ctx->call_ctx;
775 except_frame_t *except;
777 TRACE("\n");
779 except = frame->except_frame;
780 assert(except != NULL);
782 frame->except_frame = except->next;
783 heap_free(except);
784 return S_OK;
787 /* ECMA-262 3rd Edition 12.14 */
788 static HRESULT interp_end_finally(script_ctx_t *ctx)
790 jsval_t v;
792 TRACE("\n");
794 v = stack_pop(ctx);
795 assert(is_bool(v));
797 if(!get_bool(v)) {
798 TRACE("passing exception\n");
800 ctx->ei.val = stack_pop(ctx);
801 return DISP_E_EXCEPTION;
804 stack_pop(ctx);
805 return S_OK;
808 /* ECMA-262 3rd Edition 13 */
809 static HRESULT interp_func(script_ctx_t *ctx)
811 unsigned func_idx = get_op_uint(ctx, 0);
812 call_frame_t *frame = ctx->call_ctx;
813 jsdisp_t *dispex;
814 HRESULT hres;
816 TRACE("%d\n", func_idx);
818 hres = create_source_function(ctx, frame->bytecode, frame->function->funcs+func_idx,
819 frame->scope, &dispex);
820 if(FAILED(hres))
821 return hres;
823 return stack_push(ctx, jsval_obj(dispex));
826 /* ECMA-262 3rd Edition 11.2.1 */
827 static HRESULT interp_array(script_ctx_t *ctx)
829 jsstr_t *name_str;
830 const WCHAR *name;
831 jsval_t v, namev;
832 IDispatch *obj;
833 DISPID id;
834 HRESULT hres;
836 TRACE("\n");
838 namev = stack_pop(ctx);
840 hres = stack_pop_object(ctx, &obj);
841 if(FAILED(hres)) {
842 jsval_release(namev);
843 return hres;
846 hres = to_flat_string(ctx, namev, &name_str, &name);
847 jsval_release(namev);
848 if(FAILED(hres)) {
849 IDispatch_Release(obj);
850 return hres;
853 hres = disp_get_id(ctx, obj, name, NULL, 0, &id);
854 jsstr_release(name_str);
855 if(SUCCEEDED(hres)) {
856 hres = disp_propget(ctx, obj, id, &v);
857 }else if(hres == DISP_E_UNKNOWNNAME) {
858 v = jsval_undefined();
859 hres = S_OK;
861 IDispatch_Release(obj);
862 if(FAILED(hres))
863 return hres;
865 return stack_push(ctx, v);
868 /* ECMA-262 3rd Edition 11.2.1 */
869 static HRESULT interp_member(script_ctx_t *ctx)
871 const BSTR arg = get_op_bstr(ctx, 0);
872 IDispatch *obj;
873 jsval_t v;
874 DISPID id;
875 HRESULT hres;
877 TRACE("\n");
879 hres = stack_pop_object(ctx, &obj);
880 if(FAILED(hres))
881 return hres;
883 hres = disp_get_id(ctx, obj, arg, arg, 0, &id);
884 if(SUCCEEDED(hres)) {
885 hres = disp_propget(ctx, obj, id, &v);
886 }else if(hres == DISP_E_UNKNOWNNAME) {
887 v = jsval_undefined();
888 hres = S_OK;
890 IDispatch_Release(obj);
891 if(FAILED(hres))
892 return hres;
894 return stack_push(ctx, v);
897 /* ECMA-262 3rd Edition 11.2.1 */
898 static HRESULT interp_memberid(script_ctx_t *ctx)
900 const unsigned arg = get_op_uint(ctx, 0);
901 jsval_t objv, namev;
902 const WCHAR *name;
903 jsstr_t *name_str;
904 IDispatch *obj;
905 DISPID id;
906 HRESULT hres;
908 TRACE("%x\n", arg);
910 namev = stack_pop(ctx);
911 objv = stack_pop(ctx);
913 hres = to_object(ctx, objv, &obj);
914 jsval_release(objv);
915 if(SUCCEEDED(hres)) {
916 hres = to_flat_string(ctx, namev, &name_str, &name);
917 if(FAILED(hres))
918 IDispatch_Release(obj);
920 jsval_release(namev);
921 if(FAILED(hres))
922 return hres;
924 hres = disp_get_id(ctx, obj, name, NULL, arg, &id);
925 jsstr_release(name_str);
926 if(FAILED(hres)) {
927 IDispatch_Release(obj);
928 if(hres == DISP_E_UNKNOWNNAME && !(arg & fdexNameEnsure)) {
929 obj = NULL;
930 id = JS_E_INVALID_PROPERTY;
931 }else {
932 ERR("failed %08x\n", hres);
933 return hres;
937 return stack_push_objid(ctx, obj, id);
940 /* ECMA-262 3rd Edition 11.2.1 */
941 static HRESULT interp_refval(script_ctx_t *ctx)
943 IDispatch *disp;
944 jsval_t v;
945 DISPID id;
946 HRESULT hres;
948 TRACE("\n");
950 disp = stack_topn_objid(ctx, 0, &id);
951 if(!disp)
952 return throw_reference_error(ctx, JS_E_ILLEGAL_ASSIGN, NULL);
954 hres = disp_propget(ctx, disp, id, &v);
955 if(FAILED(hres))
956 return hres;
958 return stack_push(ctx, v);
961 /* ECMA-262 3rd Edition 11.2.2 */
962 static HRESULT interp_new(script_ctx_t *ctx)
964 const unsigned argc = get_op_uint(ctx, 0);
965 jsval_t r, constr;
966 HRESULT hres;
968 TRACE("%d\n", argc);
970 constr = stack_topn(ctx, argc);
972 /* NOTE: Should use to_object here */
974 if(is_null(constr))
975 return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
976 else if(!is_object_instance(constr))
977 return throw_type_error(ctx, JS_E_INVALID_ACTION, NULL);
978 else if(!get_object(constr))
979 return throw_type_error(ctx, JS_E_INVALID_PROPERTY, NULL);
981 hres = disp_call_value(ctx, get_object(constr), NULL, DISPATCH_CONSTRUCT, argc, stack_args(ctx, argc), &r);
982 if(FAILED(hres))
983 return hres;
985 stack_popn(ctx, argc+1);
986 return stack_push(ctx, r);
989 /* ECMA-262 3rd Edition 11.2.3 */
990 static HRESULT interp_call(script_ctx_t *ctx)
992 const unsigned argn = get_op_uint(ctx, 0);
993 const int do_ret = get_op_int(ctx, 1);
994 jsval_t r, obj;
995 HRESULT hres;
997 TRACE("%d %d\n", argn, do_ret);
999 obj = stack_topn(ctx, argn);
1000 if(!is_object_instance(obj))
1001 return throw_type_error(ctx, JS_E_INVALID_PROPERTY, NULL);
1003 hres = disp_call_value(ctx, get_object(obj), NULL, DISPATCH_METHOD, argn, stack_args(ctx, argn),
1004 do_ret ? &r : NULL);
1005 if(FAILED(hres))
1006 return hres;
1008 stack_popn(ctx, argn+1);
1009 return do_ret ? stack_push(ctx, r) : S_OK;
1012 /* ECMA-262 3rd Edition 11.2.3 */
1013 static HRESULT interp_call_member(script_ctx_t *ctx)
1015 const unsigned argn = get_op_uint(ctx, 0);
1016 const int do_ret = get_op_int(ctx, 1);
1017 IDispatch *obj;
1018 jsval_t r;
1019 DISPID id;
1020 HRESULT hres;
1022 TRACE("%d %d\n", argn, do_ret);
1024 obj = stack_topn_objid(ctx, argn, &id);
1025 if(!obj)
1026 return throw_type_error(ctx, id, NULL);
1028 hres = disp_call(ctx, obj, id, DISPATCH_METHOD, argn, stack_args(ctx, argn), do_ret ? &r : NULL);
1029 if(FAILED(hres))
1030 return hres;
1032 stack_popn(ctx, argn+2);
1033 return do_ret ? stack_push(ctx, r) : S_OK;
1037 /* ECMA-262 3rd Edition 11.1.1 */
1038 static HRESULT interp_this(script_ctx_t *ctx)
1040 call_frame_t *frame = ctx->call_ctx;
1042 TRACE("\n");
1044 IDispatch_AddRef(frame->this_obj);
1045 return stack_push(ctx, jsval_disp(frame->this_obj));
1048 /* ECMA-262 3rd Edition 10.1.4 */
1049 static HRESULT interp_ident(script_ctx_t *ctx)
1051 const BSTR arg = get_op_bstr(ctx, 0);
1052 exprval_t exprval;
1053 jsval_t v;
1054 HRESULT hres;
1056 TRACE("%s\n", debugstr_w(arg));
1058 hres = identifier_eval(ctx, arg, &exprval);
1059 if(FAILED(hres))
1060 return hres;
1062 if(exprval.type == EXPRVAL_INVALID)
1063 return throw_type_error(ctx, JS_E_UNDEFINED_VARIABLE, arg);
1065 hres = exprval_to_value(ctx, &exprval, &v);
1066 exprval_release(&exprval);
1067 if(FAILED(hres))
1068 return hres;
1070 return stack_push(ctx, v);
1073 /* ECMA-262 3rd Edition 10.1.4 */
1074 static HRESULT interp_identid(script_ctx_t *ctx)
1076 const BSTR arg = get_op_bstr(ctx, 0);
1077 const unsigned flags = get_op_uint(ctx, 1);
1078 exprval_t exprval;
1079 HRESULT hres;
1081 TRACE("%s %x\n", debugstr_w(arg), flags);
1083 hres = identifier_eval(ctx, arg, &exprval);
1084 if(FAILED(hres))
1085 return hres;
1087 if(exprval.type == EXPRVAL_INVALID && (flags & fdexNameEnsure)) {
1088 DISPID id;
1090 hres = jsdisp_get_id(ctx->global, arg, fdexNameEnsure, &id);
1091 if(FAILED(hres))
1092 return hres;
1094 exprval_set_idref(&exprval, to_disp(ctx->global), id);
1097 if(exprval.type != EXPRVAL_IDREF) {
1098 WARN("invalid ref\n");
1099 exprval_release(&exprval);
1100 return stack_push_objid(ctx, NULL, JS_E_OBJECT_EXPECTED);
1103 return stack_push_objid(ctx, exprval.u.idref.disp, exprval.u.idref.id);
1106 /* ECMA-262 3rd Edition 7.8.1 */
1107 static HRESULT interp_null(script_ctx_t *ctx)
1109 TRACE("\n");
1111 return stack_push(ctx, jsval_null());
1114 /* ECMA-262 3rd Edition 7.8.2 */
1115 static HRESULT interp_bool(script_ctx_t *ctx)
1117 const int arg = get_op_int(ctx, 0);
1119 TRACE("%s\n", arg ? "true" : "false");
1121 return stack_push(ctx, jsval_bool(arg));
1124 /* ECMA-262 3rd Edition 7.8.3 */
1125 static HRESULT interp_int(script_ctx_t *ctx)
1127 const int arg = get_op_int(ctx, 0);
1129 TRACE("%d\n", arg);
1131 return stack_push(ctx, jsval_number(arg));
1134 /* ECMA-262 3rd Edition 7.8.3 */
1135 static HRESULT interp_double(script_ctx_t *ctx)
1137 const double arg = get_op_double(ctx);
1139 TRACE("%lf\n", arg);
1141 return stack_push(ctx, jsval_number(arg));
1144 /* ECMA-262 3rd Edition 7.8.4 */
1145 static HRESULT interp_str(script_ctx_t *ctx)
1147 jsstr_t *str = get_op_str(ctx, 0);
1149 TRACE("%s\n", debugstr_jsstr(str));
1151 return stack_push(ctx, jsval_string(jsstr_addref(str)));
1154 /* ECMA-262 3rd Edition 7.8 */
1155 static HRESULT interp_regexp(script_ctx_t *ctx)
1157 jsstr_t *source = get_op_str(ctx, 0);
1158 const unsigned flags = get_op_uint(ctx, 1);
1159 jsdisp_t *regexp;
1160 HRESULT hres;
1162 TRACE("%s %x\n", debugstr_jsstr(source), flags);
1164 hres = create_regexp(ctx, source, flags, &regexp);
1165 if(FAILED(hres))
1166 return hres;
1168 return stack_push(ctx, jsval_obj(regexp));
1171 /* ECMA-262 3rd Edition 11.1.4 */
1172 static HRESULT interp_carray(script_ctx_t *ctx)
1174 const unsigned arg = get_op_uint(ctx, 0);
1175 jsdisp_t *array;
1176 jsval_t val;
1177 unsigned i;
1178 HRESULT hres;
1180 TRACE("%u\n", arg);
1182 hres = create_array(ctx, arg, &array);
1183 if(FAILED(hres))
1184 return hres;
1186 i = arg;
1187 while(i--) {
1188 val = stack_pop(ctx);
1189 hres = jsdisp_propput_idx(array, i, val);
1190 jsval_release(val);
1191 if(FAILED(hres)) {
1192 jsdisp_release(array);
1193 return hres;
1197 return stack_push(ctx, jsval_obj(array));
1200 /* ECMA-262 3rd Edition 11.1.5 */
1201 static HRESULT interp_new_obj(script_ctx_t *ctx)
1203 jsdisp_t *obj;
1204 HRESULT hres;
1206 TRACE("\n");
1208 hres = create_object(ctx, NULL, &obj);
1209 if(FAILED(hres))
1210 return hres;
1212 return stack_push(ctx, jsval_obj(obj));
1215 /* ECMA-262 3rd Edition 11.1.5 */
1216 static HRESULT interp_obj_prop(script_ctx_t *ctx)
1218 const BSTR name = get_op_bstr(ctx, 0);
1219 jsdisp_t *obj;
1220 jsval_t val;
1221 HRESULT hres;
1223 TRACE("%s\n", debugstr_w(name));
1225 val = stack_pop(ctx);
1227 assert(is_object_instance(stack_top(ctx)));
1228 obj = as_jsdisp(get_object(stack_top(ctx)));
1230 hres = jsdisp_propput_name(obj, name, val);
1231 jsval_release(val);
1232 return hres;
1235 /* ECMA-262 3rd Edition 11.11 */
1236 static HRESULT interp_cnd_nz(script_ctx_t *ctx)
1238 const unsigned arg = get_op_uint(ctx, 0);
1239 BOOL b;
1240 HRESULT hres;
1242 TRACE("\n");
1244 hres = to_boolean(stack_top(ctx), &b);
1245 if(FAILED(hres))
1246 return hres;
1248 if(b) {
1249 jmp_abs(ctx, arg);
1250 }else {
1251 stack_popn(ctx, 1);
1252 jmp_next(ctx);
1254 return S_OK;
1257 /* ECMA-262 3rd Edition 11.11 */
1258 static HRESULT interp_cnd_z(script_ctx_t *ctx)
1260 const unsigned arg = get_op_uint(ctx, 0);
1261 BOOL b;
1262 HRESULT hres;
1264 TRACE("\n");
1266 hres = to_boolean(stack_top(ctx), &b);
1267 if(FAILED(hres))
1268 return hres;
1270 if(b) {
1271 stack_popn(ctx, 1);
1272 jmp_next(ctx);
1273 }else {
1274 jmp_abs(ctx, arg);
1276 return S_OK;
1279 /* ECMA-262 3rd Edition 11.10 */
1280 static HRESULT interp_or(script_ctx_t *ctx)
1282 INT l, r;
1283 HRESULT hres;
1285 TRACE("\n");
1287 hres = stack_pop_int(ctx, &r);
1288 if(FAILED(hres))
1289 return hres;
1291 hres = stack_pop_int(ctx, &l);
1292 if(FAILED(hres))
1293 return hres;
1295 return stack_push(ctx, jsval_number(l|r));
1298 /* ECMA-262 3rd Edition 11.10 */
1299 static HRESULT interp_xor(script_ctx_t *ctx)
1301 INT l, r;
1302 HRESULT hres;
1304 TRACE("\n");
1306 hres = stack_pop_int(ctx, &r);
1307 if(FAILED(hres))
1308 return hres;
1310 hres = stack_pop_int(ctx, &l);
1311 if(FAILED(hres))
1312 return hres;
1314 return stack_push(ctx, jsval_number(l^r));
1317 /* ECMA-262 3rd Edition 11.10 */
1318 static HRESULT interp_and(script_ctx_t *ctx)
1320 INT l, r;
1321 HRESULT hres;
1323 TRACE("\n");
1325 hres = stack_pop_int(ctx, &r);
1326 if(FAILED(hres))
1327 return hres;
1329 hres = stack_pop_int(ctx, &l);
1330 if(FAILED(hres))
1331 return hres;
1333 return stack_push(ctx, jsval_number(l&r));
1336 /* ECMA-262 3rd Edition 11.8.6 */
1337 static HRESULT interp_instanceof(script_ctx_t *ctx)
1339 jsdisp_t *obj, *iter, *tmp = NULL;
1340 jsval_t prot, v;
1341 BOOL ret = FALSE;
1342 HRESULT hres;
1344 static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0};
1346 v = stack_pop(ctx);
1347 if(!is_object_instance(v) || !get_object(v)) {
1348 jsval_release(v);
1349 return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
1352 obj = iface_to_jsdisp((IUnknown*)get_object(v));
1353 IDispatch_Release(get_object(v));
1354 if(!obj) {
1355 FIXME("non-jsdisp objects not supported\n");
1356 return E_FAIL;
1359 if(is_class(obj, JSCLASS_FUNCTION)) {
1360 hres = jsdisp_propget_name(obj, prototypeW, &prot);
1361 }else {
1362 hres = throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
1364 jsdisp_release(obj);
1365 if(FAILED(hres))
1366 return hres;
1368 v = stack_pop(ctx);
1370 if(is_object_instance(prot)) {
1371 if(is_object_instance(v))
1372 tmp = iface_to_jsdisp((IUnknown*)get_object(v));
1373 for(iter = tmp; !ret && iter; iter = iter->prototype) {
1374 hres = disp_cmp(get_object(prot), to_disp(iter), &ret);
1375 if(FAILED(hres))
1376 break;
1379 if(tmp)
1380 jsdisp_release(tmp);
1381 }else {
1382 FIXME("prototype is not an object\n");
1383 hres = E_FAIL;
1386 jsval_release(prot);
1387 jsval_release(v);
1388 if(FAILED(hres))
1389 return hres;
1391 return stack_push(ctx, jsval_bool(ret));
1394 /* ECMA-262 3rd Edition 11.8.7 */
1395 static HRESULT interp_in(script_ctx_t *ctx)
1397 const WCHAR *str;
1398 jsstr_t *jsstr;
1399 jsval_t obj, v;
1400 DISPID id = 0;
1401 BOOL ret;
1402 HRESULT hres;
1404 TRACE("\n");
1406 obj = stack_pop(ctx);
1407 if(!is_object_instance(obj) || !get_object(obj)) {
1408 jsval_release(obj);
1409 return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
1412 v = stack_pop(ctx);
1413 hres = to_flat_string(ctx, v, &jsstr, &str);
1414 jsval_release(v);
1415 if(FAILED(hres)) {
1416 IDispatch_Release(get_object(obj));
1417 return hres;
1420 hres = disp_get_id(ctx, get_object(obj), str, NULL, 0, &id);
1421 IDispatch_Release(get_object(obj));
1422 jsstr_release(jsstr);
1423 if(SUCCEEDED(hres))
1424 ret = TRUE;
1425 else if(hres == DISP_E_UNKNOWNNAME)
1426 ret = FALSE;
1427 else
1428 return hres;
1430 return stack_push(ctx, jsval_bool(ret));
1433 /* ECMA-262 3rd Edition 11.6.1 */
1434 static HRESULT add_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, jsval_t *ret)
1436 jsval_t r, l;
1437 HRESULT hres;
1439 hres = to_primitive(ctx, lval, &l, NO_HINT);
1440 if(FAILED(hres))
1441 return hres;
1443 hres = to_primitive(ctx, rval, &r, NO_HINT);
1444 if(FAILED(hres)) {
1445 jsval_release(l);
1446 return hres;
1449 if(is_string(l) || is_string(r)) {
1450 jsstr_t *lstr, *rstr = NULL;
1452 hres = to_string(ctx, l, &lstr);
1453 if(SUCCEEDED(hres))
1454 hres = to_string(ctx, r, &rstr);
1456 if(SUCCEEDED(hres)) {
1457 jsstr_t *ret_str;
1459 ret_str = jsstr_concat(lstr, rstr);
1460 if(ret_str)
1461 *ret = jsval_string(ret_str);
1462 else
1463 hres = E_OUTOFMEMORY;
1466 jsstr_release(lstr);
1467 if(rstr)
1468 jsstr_release(rstr);
1469 }else {
1470 double nl, nr;
1472 hres = to_number(ctx, l, &nl);
1473 if(SUCCEEDED(hres)) {
1474 hres = to_number(ctx, r, &nr);
1475 if(SUCCEEDED(hres))
1476 *ret = jsval_number(nl+nr);
1480 jsval_release(r);
1481 jsval_release(l);
1482 return hres;
1485 /* ECMA-262 3rd Edition 11.6.1 */
1486 static HRESULT interp_add(script_ctx_t *ctx)
1488 jsval_t l, r, ret;
1489 HRESULT hres;
1491 r = stack_pop(ctx);
1492 l = stack_pop(ctx);
1494 TRACE("%s + %s\n", debugstr_jsval(l), debugstr_jsval(r));
1496 hres = add_eval(ctx, l, r, &ret);
1497 jsval_release(l);
1498 jsval_release(r);
1499 if(FAILED(hres))
1500 return hres;
1502 return stack_push(ctx, ret);
1505 /* ECMA-262 3rd Edition 11.6.2 */
1506 static HRESULT interp_sub(script_ctx_t *ctx)
1508 double l, r;
1509 HRESULT hres;
1511 TRACE("\n");
1513 hres = stack_pop_number(ctx, &r);
1514 if(FAILED(hres))
1515 return hres;
1517 hres = stack_pop_number(ctx, &l);
1518 if(FAILED(hres))
1519 return hres;
1521 return stack_push(ctx, jsval_number(l-r));
1524 /* ECMA-262 3rd Edition 11.5.1 */
1525 static HRESULT interp_mul(script_ctx_t *ctx)
1527 double l, r;
1528 HRESULT hres;
1530 TRACE("\n");
1532 hres = stack_pop_number(ctx, &r);
1533 if(FAILED(hres))
1534 return hres;
1536 hres = stack_pop_number(ctx, &l);
1537 if(FAILED(hres))
1538 return hres;
1540 return stack_push(ctx, jsval_number(l*r));
1543 /* ECMA-262 3rd Edition 11.5.2 */
1544 static HRESULT interp_div(script_ctx_t *ctx)
1546 double l, r;
1547 HRESULT hres;
1549 TRACE("\n");
1551 hres = stack_pop_number(ctx, &r);
1552 if(FAILED(hres))
1553 return hres;
1555 hres = stack_pop_number(ctx, &l);
1556 if(FAILED(hres))
1557 return hres;
1559 return stack_push(ctx, jsval_number(l/r));
1562 /* ECMA-262 3rd Edition 11.5.3 */
1563 static HRESULT interp_mod(script_ctx_t *ctx)
1565 double l, r;
1566 HRESULT hres;
1568 TRACE("\n");
1570 hres = stack_pop_number(ctx, &r);
1571 if(FAILED(hres))
1572 return hres;
1574 hres = stack_pop_number(ctx, &l);
1575 if(FAILED(hres))
1576 return hres;
1578 return stack_push(ctx, jsval_number(fmod(l, r)));
1581 /* ECMA-262 3rd Edition 11.4.2 */
1582 static HRESULT interp_delete(script_ctx_t *ctx)
1584 jsval_t objv, namev;
1585 IDispatch *obj;
1586 jsstr_t *name;
1587 BOOL ret;
1588 HRESULT hres;
1590 TRACE("\n");
1592 namev = stack_pop(ctx);
1593 objv = stack_pop(ctx);
1595 hres = to_object(ctx, objv, &obj);
1596 jsval_release(objv);
1597 if(FAILED(hres)) {
1598 jsval_release(namev);
1599 return hres;
1602 hres = to_string(ctx, namev, &name);
1603 jsval_release(namev);
1604 if(FAILED(hres)) {
1605 IDispatch_Release(obj);
1606 return hres;
1609 hres = disp_delete_name(ctx, obj, name, &ret);
1610 IDispatch_Release(obj);
1611 jsstr_release(name);
1612 if(FAILED(hres))
1613 return hres;
1615 return stack_push(ctx, jsval_bool(ret));
1618 /* ECMA-262 3rd Edition 11.4.2 */
1619 static HRESULT interp_delete_ident(script_ctx_t *ctx)
1621 const BSTR arg = get_op_bstr(ctx, 0);
1622 exprval_t exprval;
1623 BOOL ret;
1624 HRESULT hres;
1626 TRACE("%s\n", debugstr_w(arg));
1628 hres = identifier_eval(ctx, arg, &exprval);
1629 if(FAILED(hres))
1630 return hres;
1632 switch(exprval.type) {
1633 case EXPRVAL_IDREF:
1634 hres = disp_delete(exprval.u.idref.disp, exprval.u.idref.id, &ret);
1635 IDispatch_Release(exprval.u.idref.disp);
1636 if(FAILED(hres))
1637 return hres;
1638 break;
1639 case EXPRVAL_INVALID:
1640 ret = TRUE;
1641 break;
1642 default:
1643 FIXME("Unsupported exprval\n");
1644 exprval_release(&exprval);
1645 return E_NOTIMPL;
1649 return stack_push(ctx, jsval_bool(ret));
1652 /* ECMA-262 3rd Edition 11.4.2 */
1653 static HRESULT interp_void(script_ctx_t *ctx)
1655 TRACE("\n");
1657 stack_popn(ctx, 1);
1658 return stack_push(ctx, jsval_undefined());
1661 /* ECMA-262 3rd Edition 11.4.3 */
1662 static HRESULT typeof_string(jsval_t v, const WCHAR **ret)
1664 switch(jsval_type(v)) {
1665 case JSV_UNDEFINED:
1666 *ret = undefinedW;
1667 break;
1668 case JSV_NULL:
1669 *ret = objectW;
1670 break;
1671 case JSV_OBJECT: {
1672 jsdisp_t *dispex;
1674 if(get_object(v) && (dispex = iface_to_jsdisp((IUnknown*)get_object(v)))) {
1675 *ret = is_class(dispex, JSCLASS_FUNCTION) ? functionW : objectW;
1676 jsdisp_release(dispex);
1677 }else {
1678 *ret = objectW;
1680 break;
1682 case JSV_STRING:
1683 *ret = stringW;
1684 break;
1685 case JSV_NUMBER:
1686 *ret = numberW;
1687 break;
1688 case JSV_BOOL:
1689 *ret = booleanW;
1690 break;
1691 case JSV_VARIANT:
1692 FIXME("unhandled variant %s\n", debugstr_variant(get_variant(v)));
1693 return E_NOTIMPL;
1696 return S_OK;
1699 /* ECMA-262 3rd Edition 11.4.3 */
1700 static HRESULT interp_typeofid(script_ctx_t *ctx)
1702 const WCHAR *ret;
1703 IDispatch *obj;
1704 jsval_t v;
1705 DISPID id;
1706 HRESULT hres;
1708 TRACE("\n");
1710 obj = stack_pop_objid(ctx, &id);
1711 if(!obj)
1712 return stack_push(ctx, jsval_string(jsstr_undefined()));
1714 hres = disp_propget(ctx, obj, id, &v);
1715 IDispatch_Release(obj);
1716 if(FAILED(hres))
1717 return stack_push_string(ctx, unknownW);
1719 hres = typeof_string(v, &ret);
1720 jsval_release(v);
1721 if(FAILED(hres))
1722 return hres;
1724 return stack_push_string(ctx, ret);
1727 /* ECMA-262 3rd Edition 11.4.3 */
1728 static HRESULT interp_typeofident(script_ctx_t *ctx)
1730 const BSTR arg = get_op_bstr(ctx, 0);
1731 exprval_t exprval;
1732 const WCHAR *ret;
1733 jsval_t v;
1734 HRESULT hres;
1736 TRACE("%s\n", debugstr_w(arg));
1738 hres = identifier_eval(ctx, arg, &exprval);
1739 if(FAILED(hres))
1740 return hres;
1742 if(exprval.type == EXPRVAL_INVALID) {
1743 hres = stack_push(ctx, jsval_string(jsstr_undefined()));
1744 exprval_release(&exprval);
1745 return hres;
1748 hres = exprval_to_value(ctx, &exprval, &v);
1749 exprval_release(&exprval);
1750 if(FAILED(hres))
1751 return hres;
1753 hres = typeof_string(v, &ret);
1754 jsval_release(v);
1755 if(FAILED(hres))
1756 return hres;
1758 return stack_push_string(ctx, ret);
1761 /* ECMA-262 3rd Edition 11.4.3 */
1762 static HRESULT interp_typeof(script_ctx_t *ctx)
1764 const WCHAR *ret;
1765 jsval_t v;
1766 HRESULT hres;
1768 TRACE("\n");
1770 v = stack_pop(ctx);
1771 hres = typeof_string(v, &ret);
1772 jsval_release(v);
1773 if(FAILED(hres))
1774 return hres;
1776 return stack_push_string(ctx, ret);
1779 /* ECMA-262 3rd Edition 11.4.7 */
1780 static HRESULT interp_minus(script_ctx_t *ctx)
1782 double n;
1783 HRESULT hres;
1785 TRACE("\n");
1787 hres = stack_pop_number(ctx, &n);
1788 if(FAILED(hres))
1789 return hres;
1791 return stack_push(ctx, jsval_number(-n));
1794 /* ECMA-262 3rd Edition 11.4.6 */
1795 static HRESULT interp_tonum(script_ctx_t *ctx)
1797 jsval_t v;
1798 double n;
1799 HRESULT hres;
1801 TRACE("\n");
1803 v = stack_pop(ctx);
1804 hres = to_number(ctx, v, &n);
1805 jsval_release(v);
1806 if(FAILED(hres))
1807 return hres;
1809 return stack_push(ctx, jsval_number(n));
1812 /* ECMA-262 3rd Edition 11.3.1 */
1813 static HRESULT interp_postinc(script_ctx_t *ctx)
1815 const int arg = get_op_int(ctx, 0);
1816 IDispatch *obj;
1817 DISPID id;
1818 jsval_t v;
1819 HRESULT hres;
1821 TRACE("%d\n", arg);
1823 obj = stack_pop_objid(ctx, &id);
1824 if(!obj)
1825 return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
1827 hres = disp_propget(ctx, obj, id, &v);
1828 if(SUCCEEDED(hres)) {
1829 double n;
1831 hres = to_number(ctx, v, &n);
1832 if(SUCCEEDED(hres))
1833 hres = disp_propput(ctx, obj, id, jsval_number(n+(double)arg));
1834 if(FAILED(hres))
1835 jsval_release(v);
1837 IDispatch_Release(obj);
1838 if(FAILED(hres))
1839 return hres;
1841 return stack_push(ctx, v);
1844 /* ECMA-262 3rd Edition 11.4.4, 11.4.5 */
1845 static HRESULT interp_preinc(script_ctx_t *ctx)
1847 const int arg = get_op_int(ctx, 0);
1848 IDispatch *obj;
1849 double ret;
1850 DISPID id;
1851 jsval_t v;
1852 HRESULT hres;
1854 TRACE("%d\n", arg);
1856 obj = stack_pop_objid(ctx, &id);
1857 if(!obj)
1858 return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
1860 hres = disp_propget(ctx, obj, id, &v);
1861 if(SUCCEEDED(hres)) {
1862 double n;
1864 hres = to_number(ctx, v, &n);
1865 jsval_release(v);
1866 if(SUCCEEDED(hres)) {
1867 ret = n+(double)arg;
1868 hres = disp_propput(ctx, obj, id, jsval_number(ret));
1871 IDispatch_Release(obj);
1872 if(FAILED(hres))
1873 return hres;
1875 return stack_push(ctx, jsval_number(ret));
1878 /* ECMA-262 3rd Edition 11.9.3 */
1879 static HRESULT equal_values(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL *ret)
1881 if(jsval_type(lval) == jsval_type(rval) || (is_number(lval) && is_number(rval)))
1882 return equal2_values(lval, rval, ret);
1884 /* FIXME: NULL disps should be handled in more general way */
1885 if(is_object_instance(lval) && !get_object(lval))
1886 return equal_values(ctx, jsval_null(), rval, ret);
1887 if(is_object_instance(rval) && !get_object(rval))
1888 return equal_values(ctx, lval, jsval_null(), ret);
1890 if((is_null(lval) && is_undefined(rval)) || (is_undefined(lval) && is_null(rval))) {
1891 *ret = TRUE;
1892 return S_OK;
1895 if(is_string(lval) && is_number(rval)) {
1896 double n;
1897 HRESULT hres;
1899 hres = to_number(ctx, lval, &n);
1900 if(FAILED(hres))
1901 return hres;
1903 /* FIXME: optimize */
1904 return equal_values(ctx, jsval_number(n), rval, ret);
1907 if(is_string(rval) && is_number(lval)) {
1908 double n;
1909 HRESULT hres;
1911 hres = to_number(ctx, rval, &n);
1912 if(FAILED(hres))
1913 return hres;
1915 /* FIXME: optimize */
1916 return equal_values(ctx, lval, jsval_number(n), ret);
1919 if(is_bool(rval))
1920 return equal_values(ctx, lval, jsval_number(get_bool(rval) ? 1 : 0), ret);
1922 if(is_bool(lval))
1923 return equal_values(ctx, jsval_number(get_bool(lval) ? 1 : 0), rval, ret);
1926 if(is_object_instance(rval) && (is_string(lval) || is_number(lval))) {
1927 jsval_t prim;
1928 HRESULT hres;
1930 hres = to_primitive(ctx, rval, &prim, NO_HINT);
1931 if(FAILED(hres))
1932 return hres;
1934 hres = equal_values(ctx, lval, prim, ret);
1935 jsval_release(prim);
1936 return hres;
1940 if(is_object_instance(lval) && (is_string(rval) || is_number(rval))) {
1941 jsval_t prim;
1942 HRESULT hres;
1944 hres = to_primitive(ctx, lval, &prim, NO_HINT);
1945 if(FAILED(hres))
1946 return hres;
1948 hres = equal_values(ctx, prim, rval, ret);
1949 jsval_release(prim);
1950 return hres;
1954 *ret = FALSE;
1955 return S_OK;
1958 /* ECMA-262 3rd Edition 11.9.1 */
1959 static HRESULT interp_eq(script_ctx_t *ctx)
1961 jsval_t l, r;
1962 BOOL b;
1963 HRESULT hres;
1965 r = stack_pop(ctx);
1966 l = stack_pop(ctx);
1968 TRACE("%s == %s\n", debugstr_jsval(l), debugstr_jsval(r));
1970 hres = equal_values(ctx, l, r, &b);
1971 jsval_release(l);
1972 jsval_release(r);
1973 if(FAILED(hres))
1974 return hres;
1976 return stack_push(ctx, jsval_bool(b));
1979 /* ECMA-262 3rd Edition 11.9.2 */
1980 static HRESULT interp_neq(script_ctx_t *ctx)
1982 jsval_t l, r;
1983 BOOL b;
1984 HRESULT hres;
1986 r = stack_pop(ctx);
1987 l = stack_pop(ctx);
1989 TRACE("%s != %s\n", debugstr_jsval(l), debugstr_jsval(r));
1991 hres = equal_values(ctx, l, r, &b);
1992 jsval_release(l);
1993 jsval_release(r);
1994 if(FAILED(hres))
1995 return hres;
1997 return stack_push(ctx, jsval_bool(!b));
2000 /* ECMA-262 3rd Edition 11.9.4 */
2001 static HRESULT interp_eq2(script_ctx_t *ctx)
2003 jsval_t l, r;
2004 BOOL b;
2005 HRESULT hres;
2007 r = stack_pop(ctx);
2008 l = stack_pop(ctx);
2010 TRACE("%s === %s\n", debugstr_jsval(l), debugstr_jsval(r));
2012 hres = equal2_values(r, l, &b);
2013 jsval_release(l);
2014 jsval_release(r);
2015 if(FAILED(hres))
2016 return hres;
2018 return stack_push(ctx, jsval_bool(b));
2021 /* ECMA-262 3rd Edition 11.9.5 */
2022 static HRESULT interp_neq2(script_ctx_t *ctx)
2024 jsval_t l, r;
2025 BOOL b;
2026 HRESULT hres;
2028 TRACE("\n");
2030 r = stack_pop(ctx);
2031 l = stack_pop(ctx);
2033 hres = equal2_values(r, l, &b);
2034 jsval_release(l);
2035 jsval_release(r);
2036 if(FAILED(hres))
2037 return hres;
2039 return stack_push(ctx, jsval_bool(!b));
2042 /* ECMA-262 3rd Edition 11.8.5 */
2043 static HRESULT less_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL greater, BOOL *ret)
2045 double ln, rn;
2046 jsval_t l, r;
2047 HRESULT hres;
2049 hres = to_primitive(ctx, lval, &l, NO_HINT);
2050 if(FAILED(hres))
2051 return hres;
2053 hres = to_primitive(ctx, rval, &r, NO_HINT);
2054 if(FAILED(hres)) {
2055 jsval_release(l);
2056 return hres;
2059 if(is_string(l) && is_string(r)) {
2060 *ret = (jsstr_cmp(get_string(l), get_string(r)) < 0) ^ greater;
2061 jsstr_release(get_string(l));
2062 jsstr_release(get_string(r));
2063 return S_OK;
2066 hres = to_number(ctx, l, &ln);
2067 jsval_release(l);
2068 if(SUCCEEDED(hres))
2069 hres = to_number(ctx, r, &rn);
2070 jsval_release(r);
2071 if(FAILED(hres))
2072 return hres;
2074 *ret = !isnan(ln) && !isnan(rn) && ((ln < rn) ^ greater);
2075 return S_OK;
2078 /* ECMA-262 3rd Edition 11.8.1 */
2079 static HRESULT interp_lt(script_ctx_t *ctx)
2081 jsval_t l, r;
2082 BOOL b;
2083 HRESULT hres;
2085 r = stack_pop(ctx);
2086 l = stack_pop(ctx);
2088 TRACE("%s < %s\n", debugstr_jsval(l), debugstr_jsval(r));
2090 hres = less_eval(ctx, l, r, FALSE, &b);
2091 jsval_release(l);
2092 jsval_release(r);
2093 if(FAILED(hres))
2094 return hres;
2096 return stack_push(ctx, jsval_bool(b));
2099 /* ECMA-262 3rd Edition 11.8.1 */
2100 static HRESULT interp_lteq(script_ctx_t *ctx)
2102 jsval_t l, r;
2103 BOOL b;
2104 HRESULT hres;
2106 r = stack_pop(ctx);
2107 l = stack_pop(ctx);
2109 TRACE("%s <= %s\n", debugstr_jsval(l), debugstr_jsval(r));
2111 hres = less_eval(ctx, r, l, TRUE, &b);
2112 jsval_release(l);
2113 jsval_release(r);
2114 if(FAILED(hres))
2115 return hres;
2117 return stack_push(ctx, jsval_bool(b));
2120 /* ECMA-262 3rd Edition 11.8.2 */
2121 static HRESULT interp_gt(script_ctx_t *ctx)
2123 jsval_t l, r;
2124 BOOL b;
2125 HRESULT hres;
2127 r = stack_pop(ctx);
2128 l = stack_pop(ctx);
2130 TRACE("%s > %s\n", debugstr_jsval(l), debugstr_jsval(r));
2132 hres = less_eval(ctx, r, l, FALSE, &b);
2133 jsval_release(l);
2134 jsval_release(r);
2135 if(FAILED(hres))
2136 return hres;
2138 return stack_push(ctx, jsval_bool(b));
2141 /* ECMA-262 3rd Edition 11.8.4 */
2142 static HRESULT interp_gteq(script_ctx_t *ctx)
2144 jsval_t l, r;
2145 BOOL b;
2146 HRESULT hres;
2148 r = stack_pop(ctx);
2149 l = stack_pop(ctx);
2151 TRACE("%s >= %s\n", debugstr_jsval(l), debugstr_jsval(r));
2153 hres = less_eval(ctx, l, r, TRUE, &b);
2154 jsval_release(l);
2155 jsval_release(r);
2156 if(FAILED(hres))
2157 return hres;
2159 return stack_push(ctx, jsval_bool(b));
2162 /* ECMA-262 3rd Edition 11.4.8 */
2163 static HRESULT interp_bneg(script_ctx_t *ctx)
2165 jsval_t v;
2166 INT i;
2167 HRESULT hres;
2169 TRACE("\n");
2171 v = stack_pop(ctx);
2172 hres = to_int32(ctx, v, &i);
2173 jsval_release(v);
2174 if(FAILED(hres))
2175 return hres;
2177 return stack_push(ctx, jsval_number(~i));
2180 /* ECMA-262 3rd Edition 11.4.9 */
2181 static HRESULT interp_neg(script_ctx_t *ctx)
2183 jsval_t v;
2184 BOOL b;
2185 HRESULT hres;
2187 TRACE("\n");
2189 v = stack_pop(ctx);
2190 hres = to_boolean(v, &b);
2191 jsval_release(v);
2192 if(FAILED(hres))
2193 return hres;
2195 return stack_push(ctx, jsval_bool(!b));
2198 /* ECMA-262 3rd Edition 11.7.1 */
2199 static HRESULT interp_lshift(script_ctx_t *ctx)
2201 DWORD r;
2202 INT l;
2203 HRESULT hres;
2205 hres = stack_pop_uint(ctx, &r);
2206 if(FAILED(hres))
2207 return hres;
2209 hres = stack_pop_int(ctx, &l);
2210 if(FAILED(hres))
2211 return hres;
2213 return stack_push(ctx, jsval_number(l << (r&0x1f)));
2216 /* ECMA-262 3rd Edition 11.7.2 */
2217 static HRESULT interp_rshift(script_ctx_t *ctx)
2219 DWORD r;
2220 INT l;
2221 HRESULT hres;
2223 hres = stack_pop_uint(ctx, &r);
2224 if(FAILED(hres))
2225 return hres;
2227 hres = stack_pop_int(ctx, &l);
2228 if(FAILED(hres))
2229 return hres;
2231 return stack_push(ctx, jsval_number(l >> (r&0x1f)));
2234 /* ECMA-262 3rd Edition 11.7.3 */
2235 static HRESULT interp_rshift2(script_ctx_t *ctx)
2237 DWORD r, l;
2238 HRESULT hres;
2240 hres = stack_pop_uint(ctx, &r);
2241 if(FAILED(hres))
2242 return hres;
2244 hres = stack_pop_uint(ctx, &l);
2245 if(FAILED(hres))
2246 return hres;
2248 return stack_push(ctx, jsval_number(l >> (r&0x1f)));
2251 /* ECMA-262 3rd Edition 11.13.1 */
2252 static HRESULT interp_assign(script_ctx_t *ctx)
2254 IDispatch *disp;
2255 DISPID id;
2256 jsval_t v;
2257 HRESULT hres;
2259 TRACE("\n");
2261 v = stack_pop(ctx);
2263 disp = stack_pop_objid(ctx, &id);
2264 if(!disp) {
2265 jsval_release(v);
2266 return throw_reference_error(ctx, JS_E_ILLEGAL_ASSIGN, NULL);
2269 hres = disp_propput(ctx, disp, id, v);
2270 IDispatch_Release(disp);
2271 if(FAILED(hres)) {
2272 jsval_release(v);
2273 return hres;
2276 return stack_push(ctx, v);
2279 /* JScript extension */
2280 static HRESULT interp_assign_call(script_ctx_t *ctx)
2282 const unsigned argc = get_op_uint(ctx, 0);
2283 IDispatch *disp;
2284 jsval_t v;
2285 DISPID id;
2286 HRESULT hres;
2288 TRACE("%u\n", argc);
2290 disp = stack_topn_objid(ctx, argc+1, &id);
2291 if(!disp)
2292 return throw_reference_error(ctx, JS_E_ILLEGAL_ASSIGN, NULL);
2294 hres = disp_call(ctx, disp, id, DISPATCH_PROPERTYPUT, argc+1, stack_args(ctx, argc+1), NULL);
2295 if(FAILED(hres))
2296 return hres;
2298 v = stack_pop(ctx);
2299 stack_popn(ctx, argc+2);
2300 return stack_push(ctx, v);
2303 static HRESULT interp_undefined(script_ctx_t *ctx)
2305 TRACE("\n");
2307 return stack_push(ctx, jsval_undefined());
2310 static HRESULT interp_jmp(script_ctx_t *ctx)
2312 const unsigned arg = get_op_uint(ctx, 0);
2314 TRACE("%u\n", arg);
2316 jmp_abs(ctx, arg);
2317 return S_OK;
2320 static HRESULT interp_jmp_z(script_ctx_t *ctx)
2322 const unsigned arg = get_op_uint(ctx, 0);
2323 BOOL b;
2324 jsval_t v;
2325 HRESULT hres;
2327 TRACE("\n");
2329 v = stack_pop(ctx);
2330 hres = to_boolean(v, &b);
2331 jsval_release(v);
2332 if(FAILED(hres))
2333 return hres;
2335 if(b)
2336 jmp_next(ctx);
2337 else
2338 jmp_abs(ctx, arg);
2339 return S_OK;
2342 static HRESULT interp_pop(script_ctx_t *ctx)
2344 const unsigned arg = get_op_uint(ctx, 0);
2346 TRACE("%u\n", arg);
2348 stack_popn(ctx, arg);
2349 return S_OK;
2352 static HRESULT interp_ret(script_ctx_t *ctx)
2354 TRACE("\n");
2356 jmp_abs(ctx, -1);
2357 return S_OK;
2360 static HRESULT interp_setret(script_ctx_t *ctx)
2362 call_frame_t *frame = ctx->call_ctx;
2364 TRACE("\n");
2366 jsval_release(frame->ret);
2367 frame->ret = stack_pop(ctx);
2368 return S_OK;
2371 typedef HRESULT (*op_func_t)(script_ctx_t*);
2373 static const op_func_t op_funcs[] = {
2374 #define X(x,a,b,c) interp_##x,
2375 OP_LIST
2376 #undef X
2379 static const unsigned op_move[] = {
2380 #define X(a,x,b,c) x,
2381 OP_LIST
2382 #undef X
2385 static void release_call_frame(call_frame_t *frame)
2387 if(frame->variable_obj)
2388 jsdisp_release(frame->variable_obj);
2389 if(frame->this_obj)
2390 IDispatch_Release(frame->this_obj);
2391 if(frame->scope)
2392 scope_release(frame->scope);
2393 jsval_release(frame->ret);
2394 heap_free(frame);
2397 static HRESULT unwind_exception(script_ctx_t *ctx)
2399 call_frame_t *frame = ctx->call_ctx;
2400 except_frame_t *except_frame;
2401 jsval_t except_val;
2402 BSTR ident;
2403 HRESULT hres;
2405 except_frame = frame->except_frame;
2406 frame->except_frame = except_frame->next;
2408 assert(except_frame->stack_top <= ctx->stack_top);
2409 stack_popn(ctx, ctx->stack_top - except_frame->stack_top);
2411 while(except_frame->scope != frame->scope)
2412 scope_pop(&frame->scope);
2414 frame->ip = except_frame->catch_off;
2416 except_val = ctx->ei.val;
2417 ctx->ei.val = jsval_undefined();
2418 clear_ei(ctx);
2420 ident = except_frame->ident;
2421 heap_free(except_frame);
2423 if(ident) {
2424 jsdisp_t *scope_obj;
2426 hres = create_dispex(ctx, NULL, NULL, &scope_obj);
2427 if(SUCCEEDED(hres)) {
2428 hres = jsdisp_propput_name(scope_obj, ident, except_val);
2429 if(FAILED(hres))
2430 jsdisp_release(scope_obj);
2432 jsval_release(except_val);
2433 if(FAILED(hres))
2434 return hres;
2436 hres = scope_push(frame->scope, scope_obj, to_disp(scope_obj), &frame->scope);
2437 jsdisp_release(scope_obj);
2438 }else {
2439 hres = stack_push(ctx, except_val);
2440 if(FAILED(hres))
2441 return hres;
2443 hres = stack_push(ctx, jsval_bool(FALSE));
2446 return hres;
2449 static HRESULT enter_bytecode(script_ctx_t *ctx, function_code_t *func, jsval_t *ret)
2451 call_frame_t *frame;
2452 jsop_t op;
2453 HRESULT hres = S_OK;
2455 TRACE("\n");
2457 frame = ctx->call_ctx;
2459 while(frame->ip != -1) {
2460 op = frame->bytecode->instrs[frame->ip].op;
2461 hres = op_funcs[op](ctx);
2462 if(FAILED(hres)) {
2463 TRACE("EXCEPTION %08x\n", hres);
2465 if(!frame->except_frame)
2466 break;
2468 hres = unwind_exception(ctx);
2469 if(FAILED(hres))
2470 break;
2471 }else {
2472 frame->ip += op_move[op];
2476 assert(ctx->call_ctx == frame);
2478 if(FAILED(hres)) {
2479 while(frame->scope != frame->base_scope)
2480 scope_pop(&frame->scope);
2481 stack_popn(ctx, ctx->stack_top-frame->stack_base);
2484 assert(ctx->stack_top == frame->stack_base);
2485 assert(frame->scope == frame->base_scope);
2486 ctx->call_ctx = frame->prev_frame;
2488 if(SUCCEEDED(hres)) {
2489 *ret = frame->ret;
2490 frame->ret = jsval_undefined();
2493 release_call_frame(frame);
2494 return hres;
2497 static HRESULT bind_event_target(script_ctx_t *ctx, function_code_t *func, jsdisp_t *func_obj)
2499 IBindEventHandler *target;
2500 exprval_t exprval;
2501 IDispatch *disp;
2502 jsval_t v;
2503 HRESULT hres;
2505 hres = identifier_eval(ctx, func->event_target, &exprval);
2506 if(FAILED(hres))
2507 return hres;
2509 hres = exprval_to_value(ctx, &exprval, &v);
2510 exprval_release(&exprval);
2511 if(FAILED(hres))
2512 return hres;
2514 if(!is_object_instance(v)) {
2515 FIXME("Can't bind to %s\n", debugstr_jsval(v));
2516 jsval_release(v);
2519 disp = get_object(v);
2520 hres = IDispatch_QueryInterface(disp, &IID_IBindEventHandler, (void**)&target);
2521 if(SUCCEEDED(hres)) {
2522 hres = IBindEventHandler_BindHandler(target, func->name, (IDispatch*)&func_obj->IDispatchEx_iface);
2523 IBindEventHandler_Release(target);
2524 if(FAILED(hres))
2525 WARN("BindEvent failed: %08x\n", hres);
2526 }else {
2527 FIXME("No IBindEventHandler, not yet supported binding\n");
2530 IDispatch_Release(disp);
2531 return hres;
2534 static HRESULT setup_call_frame(exec_ctx_t *ctx, bytecode_t *bytecode, function_code_t *function, scope_chain_t *scope,
2535 IDispatch *this_obj, jsdisp_t *variable_obj)
2537 call_frame_t *frame;
2539 /* ECMA-262 3rd Edition 11.2.3.7 */
2540 if(this_obj) {
2541 jsdisp_t *jsthis;
2543 jsthis = iface_to_jsdisp((IUnknown*)this_obj);
2544 if(jsthis) {
2545 if(jsthis->builtin_info->class == JSCLASS_GLOBAL || jsthis->builtin_info->class == JSCLASS_NONE)
2546 this_obj = NULL;
2547 jsdisp_release(jsthis);
2551 frame = heap_alloc_zero(sizeof(*frame));
2552 if(!frame)
2553 return E_OUTOFMEMORY;
2555 frame->bytecode = bytecode;
2556 frame->function = function;
2557 frame->ip = function->instr_off;
2558 frame->stack_base = ctx->script->stack_top;
2559 frame->ret = jsval_undefined();
2561 if(scope)
2562 frame->base_scope = frame->scope = scope_addref(scope);
2564 if(this_obj)
2565 frame->this_obj = this_obj;
2566 else if(ctx->script->host_global)
2567 frame->this_obj = ctx->script->host_global;
2568 else
2569 frame->this_obj = to_disp(ctx->script->global);
2570 IDispatch_AddRef(frame->this_obj);
2572 frame->variable_obj = jsdisp_addref(variable_obj);
2574 frame->exec_ctx = ctx;
2576 frame->prev_frame = ctx->script->call_ctx;
2577 ctx->script->call_ctx = frame;
2578 return S_OK;
2581 HRESULT exec_source(exec_ctx_t *ctx, bytecode_t *code, function_code_t *func, scope_chain_t *scope,
2582 IDispatch *this_obj, jsdisp_t *variable_obj, jsval_t *ret)
2584 jsval_t val;
2585 unsigned i;
2586 HRESULT hres = S_OK;
2588 for(i = 0; i < func->func_cnt; i++) {
2589 jsdisp_t *func_obj;
2591 if(!func->funcs[i].name)
2592 continue;
2594 hres = create_source_function(ctx->script, code, func->funcs+i, scope, &func_obj);
2595 if(FAILED(hres))
2596 return hres;
2598 if(func->funcs[i].event_target)
2599 hres = bind_event_target(ctx->script, func->funcs+i, func_obj);
2600 else
2601 hres = jsdisp_propput_name(variable_obj, func->funcs[i].name, jsval_obj(func_obj));
2602 jsdisp_release(func_obj);
2603 if(FAILED(hres))
2604 return hres;
2607 for(i=0; i < func->var_cnt; i++) {
2608 if(!ctx->is_global || !lookup_global_members(ctx->script, func->variables[i], NULL)) {
2609 DISPID id = 0;
2611 hres = jsdisp_get_id(variable_obj, func->variables[i], fdexNameEnsure, &id);
2612 if(FAILED(hres))
2613 return hres;
2617 hres = setup_call_frame(ctx, code, func, scope, this_obj, variable_obj);
2618 if(FAILED(hres))
2619 return hres;
2621 hres = enter_bytecode(ctx->script, func, &val);
2622 if(FAILED(hres))
2623 return hres;
2625 if(ret)
2626 *ret = val;
2627 else
2628 jsval_release(val);
2629 return S_OK;