ddraw/tests: Add some tests for the properties of the DC returned by surface GetDC().
[wine.git] / dlls / jscript / engine.c
blob74cef15e400548ce00ef5457a22d12b17ed1955b
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 inline jsval_t steal_ret(call_frame_t *frame)
199 jsval_t r = frame->ret;
200 frame->ret = jsval_undefined();
201 return r;
204 static inline void clear_ret(call_frame_t *frame)
206 jsval_release(steal_ret(frame));
209 static void exprval_release(exprval_t *val)
211 switch(val->type) {
212 case EXPRVAL_JSVAL:
213 jsval_release(val->u.val);
214 return;
215 case EXPRVAL_IDREF:
216 if(val->u.idref.disp)
217 IDispatch_Release(val->u.idref.disp);
218 return;
219 case EXPRVAL_INVALID:
220 return;
224 /* ECMA-262 3rd Edition 8.7.1 */
225 static HRESULT exprval_to_value(script_ctx_t *ctx, exprval_t *val, jsval_t *ret)
227 switch(val->type) {
228 case EXPRVAL_JSVAL:
229 *ret = val->u.val;
230 val->u.val = jsval_undefined();
231 return S_OK;
232 case EXPRVAL_IDREF:
233 if(!val->u.idref.disp) {
234 FIXME("throw ReferenceError\n");
235 return E_FAIL;
238 return disp_propget(ctx, val->u.idref.disp, val->u.idref.id, ret);
239 case EXPRVAL_INVALID:
240 assert(0);
243 ERR("type %d\n", val->type);
244 return E_FAIL;
247 static void exprval_set_idref(exprval_t *val, IDispatch *disp, DISPID id)
249 val->type = EXPRVAL_IDREF;
250 val->u.idref.disp = disp;
251 val->u.idref.id = id;
253 if(disp)
254 IDispatch_AddRef(disp);
257 HRESULT scope_push(scope_chain_t *scope, jsdisp_t *jsobj, IDispatch *obj, scope_chain_t **ret)
259 scope_chain_t *new_scope;
261 new_scope = heap_alloc(sizeof(scope_chain_t));
262 if(!new_scope)
263 return E_OUTOFMEMORY;
265 new_scope->ref = 1;
267 IDispatch_AddRef(obj);
268 new_scope->jsobj = jsobj;
269 new_scope->obj = obj;
271 if(scope) {
272 scope_addref(scope);
273 new_scope->next = scope;
274 }else {
275 new_scope->next = NULL;
278 *ret = new_scope;
279 return S_OK;
282 static void scope_pop(scope_chain_t **scope)
284 scope_chain_t *tmp;
286 tmp = *scope;
287 *scope = tmp->next;
288 scope_release(tmp);
291 void clear_ei(script_ctx_t *ctx)
293 memset(&ctx->ei.ei, 0, sizeof(ctx->ei.ei));
294 jsval_release(ctx->ei.val);
295 ctx->ei.val = jsval_undefined();
298 void scope_release(scope_chain_t *scope)
300 if(--scope->ref)
301 return;
303 if(scope->next)
304 scope_release(scope->next);
306 IDispatch_Release(scope->obj);
307 heap_free(scope);
310 static HRESULT disp_get_id(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name, BSTR name_bstr, DWORD flags, DISPID *id)
312 IDispatchEx *dispex;
313 jsdisp_t *jsdisp;
314 BSTR bstr;
315 HRESULT hres;
317 jsdisp = iface_to_jsdisp((IUnknown*)disp);
318 if(jsdisp) {
319 hres = jsdisp_get_id(jsdisp, name, flags, id);
320 jsdisp_release(jsdisp);
321 return hres;
324 if(name_bstr) {
325 bstr = name_bstr;
326 }else {
327 bstr = SysAllocString(name);
328 if(!bstr)
329 return E_OUTOFMEMORY;
332 *id = 0;
333 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
334 if(SUCCEEDED(hres)) {
335 hres = IDispatchEx_GetDispID(dispex, bstr, make_grfdex(ctx, flags|fdexNameCaseSensitive), id);
336 IDispatchEx_Release(dispex);
337 }else {
338 TRACE("using IDispatch\n");
339 hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, id);
342 if(name_bstr != bstr)
343 SysFreeString(bstr);
344 return hres;
347 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, BOOL *ret)
349 IObjectIdentity *identity;
350 IUnknown *unk1, *unk2;
351 HRESULT hres;
353 if(disp1 == disp2) {
354 *ret = TRUE;
355 return S_OK;
358 if(!disp1 || !disp2) {
359 *ret = FALSE;
360 return S_OK;
363 hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
364 if(FAILED(hres))
365 return hres;
367 hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
368 if(FAILED(hres)) {
369 IUnknown_Release(unk1);
370 return hres;
373 if(unk1 == unk2) {
374 *ret = TRUE;
375 }else {
376 hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
377 if(SUCCEEDED(hres)) {
378 hres = IObjectIdentity_IsEqualObject(identity, unk2);
379 IObjectIdentity_Release(identity);
380 *ret = hres == S_OK;
381 }else {
382 *ret = FALSE;
386 IUnknown_Release(unk1);
387 IUnknown_Release(unk2);
388 return S_OK;
391 /* ECMA-262 3rd Edition 11.9.6 */
392 static HRESULT equal2_values(jsval_t lval, jsval_t rval, BOOL *ret)
394 jsval_type_t type = jsval_type(lval);
396 TRACE("\n");
398 if(type != jsval_type(rval)) {
399 if(is_null_instance(lval))
400 *ret = is_null_instance(rval);
401 else
402 *ret = FALSE;
403 return S_OK;
406 switch(type) {
407 case JSV_UNDEFINED:
408 case JSV_NULL:
409 *ret = TRUE;
410 break;
411 case JSV_OBJECT:
412 return disp_cmp(get_object(lval), get_object(rval), ret);
413 case JSV_STRING:
414 *ret = jsstr_eq(get_string(lval), get_string(rval));
415 break;
416 case JSV_NUMBER:
417 *ret = get_number(lval) == get_number(rval);
418 break;
419 case JSV_BOOL:
420 *ret = !get_bool(lval) == !get_bool(rval);
421 break;
422 case JSV_VARIANT:
423 FIXME("VARIANT not implemented\n");
424 return E_NOTIMPL;
427 return S_OK;
430 static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
432 named_item_t *item;
433 DISPID id;
434 HRESULT hres;
436 for(item = ctx->named_items; item; item = item->next) {
437 if(item->flags & SCRIPTITEM_GLOBALMEMBERS) {
438 hres = disp_get_id(ctx, item->disp, identifier, identifier, 0, &id);
439 if(SUCCEEDED(hres)) {
440 if(ret)
441 exprval_set_idref(ret, item->disp, id);
442 return TRUE;
447 return FALSE;
450 /* ECMA-262 3rd Edition 10.1.4 */
451 static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
453 scope_chain_t *scope;
454 named_item_t *item;
455 DISPID id = 0;
456 HRESULT hres;
458 TRACE("%s\n", debugstr_w(identifier));
460 if(ctx->call_ctx) {
461 for(scope = ctx->call_ctx->scope; scope; scope = scope->next) {
462 if(scope->jsobj)
463 hres = jsdisp_get_id(scope->jsobj, identifier, fdexNameImplicit, &id);
464 else
465 hres = disp_get_id(ctx, scope->obj, identifier, identifier, fdexNameImplicit, &id);
466 if(SUCCEEDED(hres)) {
467 exprval_set_idref(ret, scope->obj, id);
468 return S_OK;
473 hres = jsdisp_get_id(ctx->global, identifier, 0, &id);
474 if(SUCCEEDED(hres)) {
475 exprval_set_idref(ret, to_disp(ctx->global), id);
476 return S_OK;
479 for(item = ctx->named_items; item; item = item->next) {
480 if((item->flags & SCRIPTITEM_ISVISIBLE) && !strcmpW(item->name, identifier)) {
481 if(!item->disp) {
482 IUnknown *unk;
484 if(!ctx->site)
485 break;
487 hres = IActiveScriptSite_GetItemInfo(ctx->site, identifier,
488 SCRIPTINFO_IUNKNOWN, &unk, NULL);
489 if(FAILED(hres)) {
490 WARN("GetItemInfo failed: %08x\n", hres);
491 break;
494 hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp);
495 IUnknown_Release(unk);
496 if(FAILED(hres)) {
497 WARN("object does not implement IDispatch\n");
498 break;
502 IDispatch_AddRef(item->disp);
503 ret->type = EXPRVAL_JSVAL;
504 ret->u.val = jsval_disp(item->disp);
505 return S_OK;
509 if(lookup_global_members(ctx, identifier, ret))
510 return S_OK;
512 ret->type = EXPRVAL_INVALID;
513 return S_OK;
516 static inline BSTR get_op_bstr(script_ctx_t *ctx, int i)
518 call_frame_t *frame = ctx->call_ctx;
519 return frame->bytecode->instrs[frame->ip].u.arg[i].bstr;
522 static inline unsigned get_op_uint(script_ctx_t *ctx, int i)
524 call_frame_t *frame = ctx->call_ctx;
525 return frame->bytecode->instrs[frame->ip].u.arg[i].uint;
528 static inline unsigned get_op_int(script_ctx_t *ctx, int i)
530 call_frame_t *frame = ctx->call_ctx;
531 return frame->bytecode->instrs[frame->ip].u.arg[i].lng;
534 static inline jsstr_t *get_op_str(script_ctx_t *ctx, int i)
536 call_frame_t *frame = ctx->call_ctx;
537 return frame->bytecode->instrs[frame->ip].u.arg[i].str;
540 static inline double get_op_double(script_ctx_t *ctx)
542 call_frame_t *frame = ctx->call_ctx;
543 return frame->bytecode->instrs[frame->ip].u.dbl;
546 static inline void jmp_next(script_ctx_t *ctx)
548 ctx->call_ctx->ip++;
551 static inline void jmp_abs(script_ctx_t *ctx, unsigned dst)
553 ctx->call_ctx->ip = dst;
556 /* ECMA-262 3rd Edition 12.2 */
557 static HRESULT interp_var_set(script_ctx_t *ctx)
559 const BSTR name = get_op_bstr(ctx, 0);
560 jsval_t val;
561 HRESULT hres;
563 TRACE("%s\n", debugstr_w(name));
565 val = stack_pop(ctx);
566 hres = jsdisp_propput_name(ctx->call_ctx->variable_obj, name, val);
567 jsval_release(val);
568 return hres;
571 /* ECMA-262 3rd Edition 12.6.4 */
572 static HRESULT interp_forin(script_ctx_t *ctx)
574 const HRESULT arg = get_op_uint(ctx, 0);
575 IDispatch *var_obj, *obj = NULL;
576 IDispatchEx *dispex;
577 DISPID id, var_id;
578 BSTR name = NULL;
579 HRESULT hres;
581 TRACE("\n");
583 assert(is_number(stack_top(ctx)));
584 id = get_number(stack_top(ctx));
586 var_obj = stack_topn_objid(ctx, 1, &var_id);
587 if(!var_obj) {
588 FIXME("invalid ref\n");
589 return E_FAIL;
592 if(is_object_instance(stack_topn(ctx, 3)))
593 obj = get_object(stack_topn(ctx, 3));
595 if(obj) {
596 hres = IDispatch_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
597 if(SUCCEEDED(hres)) {
598 hres = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, id, &id);
599 if(hres == S_OK)
600 hres = IDispatchEx_GetMemberName(dispex, id, &name);
601 IDispatchEx_Release(dispex);
602 if(FAILED(hres))
603 return hres;
604 }else {
605 TRACE("No IDispatchEx\n");
609 if(name) {
610 jsstr_t *str;
612 str = jsstr_alloc_len(name, SysStringLen(name));
613 SysFreeString(name);
614 if(!str)
615 return E_OUTOFMEMORY;
617 stack_pop(ctx);
618 stack_push(ctx, jsval_number(id)); /* safe, just after pop() */
620 hres = disp_propput(ctx, var_obj, var_id, jsval_string(str));
621 jsstr_release(str);
622 if(FAILED(hres))
623 return hres;
625 jmp_next(ctx);
626 }else {
627 stack_popn(ctx, 4);
628 jmp_abs(ctx, arg);
630 return S_OK;
633 /* ECMA-262 3rd Edition 12.10 */
634 static HRESULT interp_push_scope(script_ctx_t *ctx)
636 IDispatch *disp;
637 jsval_t v;
638 HRESULT hres;
640 TRACE("\n");
642 v = stack_pop(ctx);
643 hres = to_object(ctx, v, &disp);
644 jsval_release(v);
645 if(FAILED(hres))
646 return hres;
648 hres = scope_push(ctx->call_ctx->scope, to_jsdisp(disp), disp, &ctx->call_ctx->scope);
649 IDispatch_Release(disp);
650 return hres;
653 /* ECMA-262 3rd Edition 12.10 */
654 static HRESULT interp_pop_scope(script_ctx_t *ctx)
656 TRACE("\n");
658 scope_pop(&ctx->call_ctx->scope);
659 return S_OK;
662 /* ECMA-262 3rd Edition 12.13 */
663 static HRESULT interp_case(script_ctx_t *ctx)
665 const unsigned arg = get_op_uint(ctx, 0);
666 jsval_t v;
667 BOOL b;
668 HRESULT hres;
670 TRACE("\n");
672 v = stack_pop(ctx);
673 hres = equal2_values(stack_top(ctx), v, &b);
674 jsval_release(v);
675 if(FAILED(hres))
676 return hres;
678 if(b) {
679 stack_popn(ctx, 1);
680 jmp_abs(ctx, arg);
681 }else {
682 jmp_next(ctx);
684 return S_OK;
687 /* ECMA-262 3rd Edition 12.13 */
688 static HRESULT interp_throw(script_ctx_t *ctx)
690 TRACE("\n");
692 jsval_release(ctx->ei.val);
693 ctx->ei.val = stack_pop(ctx);
694 return DISP_E_EXCEPTION;
697 static HRESULT interp_throw_ref(script_ctx_t *ctx)
699 const HRESULT arg = get_op_uint(ctx, 0);
701 TRACE("%08x\n", arg);
703 return throw_reference_error(ctx, arg, NULL);
706 static HRESULT interp_throw_type(script_ctx_t *ctx)
708 const HRESULT hres = get_op_uint(ctx, 0);
709 jsstr_t *str = get_op_str(ctx, 1);
710 const WCHAR *ptr;
712 TRACE("%08x %s\n", hres, debugstr_jsstr(str));
714 ptr = jsstr_flatten(str);
715 return ptr ? throw_type_error(ctx, hres, ptr) : E_OUTOFMEMORY;
718 /* ECMA-262 3rd Edition 12.14 */
719 static HRESULT interp_push_except(script_ctx_t *ctx)
721 const unsigned arg1 = get_op_uint(ctx, 0);
722 const BSTR arg2 = get_op_bstr(ctx, 1);
723 call_frame_t *frame = ctx->call_ctx;
724 except_frame_t *except;
725 unsigned stack_top;
727 TRACE("\n");
729 stack_top = ctx->stack_top;
731 if(!arg2) {
732 HRESULT hres;
734 hres = stack_push(ctx, jsval_bool(TRUE));
735 if(FAILED(hres))
736 return hres;
737 hres = stack_push(ctx, jsval_bool(TRUE));
738 if(FAILED(hres))
739 return hres;
742 except = heap_alloc(sizeof(*except));
743 if(!except)
744 return E_OUTOFMEMORY;
746 except->stack_top = stack_top;
747 except->scope = frame->scope;
748 except->catch_off = arg1;
749 except->ident = arg2;
750 except->next = frame->except_frame;
751 frame->except_frame = except;
752 return S_OK;
755 /* ECMA-262 3rd Edition 12.14 */
756 static HRESULT interp_pop_except(script_ctx_t *ctx)
758 call_frame_t *frame = ctx->call_ctx;
759 except_frame_t *except;
761 TRACE("\n");
763 except = frame->except_frame;
764 assert(except != NULL);
766 frame->except_frame = except->next;
767 heap_free(except);
768 return S_OK;
771 /* ECMA-262 3rd Edition 12.14 */
772 static HRESULT interp_end_finally(script_ctx_t *ctx)
774 jsval_t v;
776 TRACE("\n");
778 v = stack_pop(ctx);
779 assert(is_bool(v));
781 if(!get_bool(v)) {
782 TRACE("passing exception\n");
784 ctx->ei.val = stack_pop(ctx);
785 return DISP_E_EXCEPTION;
788 stack_pop(ctx);
789 return S_OK;
792 /* ECMA-262 3rd Edition 13 */
793 static HRESULT interp_func(script_ctx_t *ctx)
795 unsigned func_idx = get_op_uint(ctx, 0);
796 call_frame_t *frame = ctx->call_ctx;
797 jsdisp_t *dispex;
798 HRESULT hres;
800 TRACE("%d\n", func_idx);
802 hres = create_source_function(ctx, frame->bytecode, frame->function->funcs+func_idx,
803 frame->scope, &dispex);
804 if(FAILED(hres))
805 return hres;
807 return stack_push(ctx, jsval_obj(dispex));
810 /* ECMA-262 3rd Edition 11.2.1 */
811 static HRESULT interp_array(script_ctx_t *ctx)
813 jsstr_t *name_str;
814 const WCHAR *name;
815 jsval_t v, namev;
816 IDispatch *obj;
817 DISPID id;
818 HRESULT hres;
820 TRACE("\n");
822 namev = stack_pop(ctx);
824 hres = stack_pop_object(ctx, &obj);
825 if(FAILED(hres)) {
826 jsval_release(namev);
827 return hres;
830 hres = to_flat_string(ctx, namev, &name_str, &name);
831 jsval_release(namev);
832 if(FAILED(hres)) {
833 IDispatch_Release(obj);
834 return hres;
837 hres = disp_get_id(ctx, obj, name, NULL, 0, &id);
838 jsstr_release(name_str);
839 if(SUCCEEDED(hres)) {
840 hres = disp_propget(ctx, obj, id, &v);
841 }else if(hres == DISP_E_UNKNOWNNAME) {
842 v = jsval_undefined();
843 hres = S_OK;
845 IDispatch_Release(obj);
846 if(FAILED(hres))
847 return hres;
849 return stack_push(ctx, v);
852 /* ECMA-262 3rd Edition 11.2.1 */
853 static HRESULT interp_member(script_ctx_t *ctx)
855 const BSTR arg = get_op_bstr(ctx, 0);
856 IDispatch *obj;
857 jsval_t v;
858 DISPID id;
859 HRESULT hres;
861 TRACE("\n");
863 hres = stack_pop_object(ctx, &obj);
864 if(FAILED(hres))
865 return hres;
867 hres = disp_get_id(ctx, obj, arg, arg, 0, &id);
868 if(SUCCEEDED(hres)) {
869 hres = disp_propget(ctx, obj, id, &v);
870 }else if(hres == DISP_E_UNKNOWNNAME) {
871 v = jsval_undefined();
872 hres = S_OK;
874 IDispatch_Release(obj);
875 if(FAILED(hres))
876 return hres;
878 return stack_push(ctx, v);
881 /* ECMA-262 3rd Edition 11.2.1 */
882 static HRESULT interp_memberid(script_ctx_t *ctx)
884 const unsigned arg = get_op_uint(ctx, 0);
885 jsval_t objv, namev;
886 const WCHAR *name;
887 jsstr_t *name_str;
888 IDispatch *obj;
889 DISPID id;
890 HRESULT hres;
892 TRACE("%x\n", arg);
894 namev = stack_pop(ctx);
895 objv = stack_pop(ctx);
897 hres = to_object(ctx, objv, &obj);
898 jsval_release(objv);
899 if(SUCCEEDED(hres)) {
900 hres = to_flat_string(ctx, namev, &name_str, &name);
901 if(FAILED(hres))
902 IDispatch_Release(obj);
904 jsval_release(namev);
905 if(FAILED(hres))
906 return hres;
908 hres = disp_get_id(ctx, obj, name, NULL, arg, &id);
909 jsstr_release(name_str);
910 if(FAILED(hres)) {
911 IDispatch_Release(obj);
912 if(hres == DISP_E_UNKNOWNNAME && !(arg & fdexNameEnsure)) {
913 obj = NULL;
914 id = JS_E_INVALID_PROPERTY;
915 }else {
916 ERR("failed %08x\n", hres);
917 return hres;
921 return stack_push_objid(ctx, obj, id);
924 /* ECMA-262 3rd Edition 11.2.1 */
925 static HRESULT interp_refval(script_ctx_t *ctx)
927 IDispatch *disp;
928 jsval_t v;
929 DISPID id;
930 HRESULT hres;
932 TRACE("\n");
934 disp = stack_topn_objid(ctx, 0, &id);
935 if(!disp)
936 return throw_reference_error(ctx, JS_E_ILLEGAL_ASSIGN, NULL);
938 hres = disp_propget(ctx, disp, id, &v);
939 if(FAILED(hres))
940 return hres;
942 return stack_push(ctx, v);
945 /* ECMA-262 3rd Edition 11.2.2 */
946 static HRESULT interp_new(script_ctx_t *ctx)
948 const unsigned argc = get_op_uint(ctx, 0);
949 call_frame_t *frame = ctx->call_ctx;
950 jsval_t constr;
952 TRACE("%d\n", argc);
954 constr = stack_topn(ctx, argc);
956 /* NOTE: Should use to_object here */
958 if(is_null(constr))
959 return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
960 else if(!is_object_instance(constr))
961 return throw_type_error(ctx, JS_E_INVALID_ACTION, NULL);
962 else if(!get_object(constr))
963 return throw_type_error(ctx, JS_E_INVALID_PROPERTY, NULL);
965 clear_ret(frame);
966 return disp_call_value(ctx, get_object(constr), NULL, DISPATCH_CONSTRUCT | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
967 argc, stack_args(ctx, argc), &frame->ret);
970 /* ECMA-262 3rd Edition 11.2.3 */
971 static HRESULT interp_call(script_ctx_t *ctx)
973 const unsigned argn = get_op_uint(ctx, 0);
974 const int do_ret = get_op_int(ctx, 1);
975 call_frame_t *frame = ctx->call_ctx;
976 jsval_t obj;
978 TRACE("%d %d\n", argn, do_ret);
980 obj = stack_topn(ctx, argn);
981 if(!is_object_instance(obj))
982 return throw_type_error(ctx, JS_E_INVALID_PROPERTY, NULL);
984 clear_ret(frame);
985 return disp_call_value(ctx, get_object(obj), NULL, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
986 argn, stack_args(ctx, argn), do_ret ? &frame->ret : NULL);
989 /* ECMA-262 3rd Edition 11.2.3 */
990 static HRESULT interp_call_member(script_ctx_t *ctx)
992 const unsigned argn = get_op_uint(ctx, 0);
993 const int do_ret = get_op_int(ctx, 1);
994 call_frame_t *frame = ctx->call_ctx;
995 IDispatch *obj;
996 DISPID id;
998 TRACE("%d %d\n", argn, do_ret);
1000 obj = stack_topn_objid(ctx, argn, &id);
1001 if(!obj)
1002 return throw_type_error(ctx, id, NULL);
1004 clear_ret(frame);
1005 return disp_call(ctx, obj, id, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
1006 argn, stack_args(ctx, argn), do_ret ? &frame->ret : NULL);
1009 /* ECMA-262 3rd Edition 11.1.1 */
1010 static HRESULT interp_this(script_ctx_t *ctx)
1012 call_frame_t *frame = ctx->call_ctx;
1014 TRACE("\n");
1016 IDispatch_AddRef(frame->this_obj);
1017 return stack_push(ctx, jsval_disp(frame->this_obj));
1020 /* ECMA-262 3rd Edition 10.1.4 */
1021 static HRESULT interp_ident(script_ctx_t *ctx)
1023 const BSTR arg = get_op_bstr(ctx, 0);
1024 exprval_t exprval;
1025 jsval_t v;
1026 HRESULT hres;
1028 TRACE("%s\n", debugstr_w(arg));
1030 hres = identifier_eval(ctx, arg, &exprval);
1031 if(FAILED(hres))
1032 return hres;
1034 if(exprval.type == EXPRVAL_INVALID)
1035 return throw_type_error(ctx, JS_E_UNDEFINED_VARIABLE, arg);
1037 hres = exprval_to_value(ctx, &exprval, &v);
1038 exprval_release(&exprval);
1039 if(FAILED(hres))
1040 return hres;
1042 return stack_push(ctx, v);
1045 /* ECMA-262 3rd Edition 10.1.4 */
1046 static HRESULT interp_identid(script_ctx_t *ctx)
1048 const BSTR arg = get_op_bstr(ctx, 0);
1049 const unsigned flags = get_op_uint(ctx, 1);
1050 exprval_t exprval;
1051 HRESULT hres;
1053 TRACE("%s %x\n", debugstr_w(arg), flags);
1055 hres = identifier_eval(ctx, arg, &exprval);
1056 if(FAILED(hres))
1057 return hres;
1059 if(exprval.type == EXPRVAL_INVALID && (flags & fdexNameEnsure)) {
1060 DISPID id;
1062 hres = jsdisp_get_id(ctx->global, arg, fdexNameEnsure, &id);
1063 if(FAILED(hres))
1064 return hres;
1066 exprval_set_idref(&exprval, to_disp(ctx->global), id);
1069 if(exprval.type != EXPRVAL_IDREF) {
1070 WARN("invalid ref\n");
1071 exprval_release(&exprval);
1072 return stack_push_objid(ctx, NULL, JS_E_OBJECT_EXPECTED);
1075 return stack_push_objid(ctx, exprval.u.idref.disp, exprval.u.idref.id);
1078 /* ECMA-262 3rd Edition 7.8.1 */
1079 static HRESULT interp_null(script_ctx_t *ctx)
1081 TRACE("\n");
1083 return stack_push(ctx, jsval_null());
1086 /* ECMA-262 3rd Edition 7.8.2 */
1087 static HRESULT interp_bool(script_ctx_t *ctx)
1089 const int arg = get_op_int(ctx, 0);
1091 TRACE("%s\n", arg ? "true" : "false");
1093 return stack_push(ctx, jsval_bool(arg));
1096 /* ECMA-262 3rd Edition 7.8.3 */
1097 static HRESULT interp_int(script_ctx_t *ctx)
1099 const int arg = get_op_int(ctx, 0);
1101 TRACE("%d\n", arg);
1103 return stack_push(ctx, jsval_number(arg));
1106 /* ECMA-262 3rd Edition 7.8.3 */
1107 static HRESULT interp_double(script_ctx_t *ctx)
1109 const double arg = get_op_double(ctx);
1111 TRACE("%lf\n", arg);
1113 return stack_push(ctx, jsval_number(arg));
1116 /* ECMA-262 3rd Edition 7.8.4 */
1117 static HRESULT interp_str(script_ctx_t *ctx)
1119 jsstr_t *str = get_op_str(ctx, 0);
1121 TRACE("%s\n", debugstr_jsstr(str));
1123 return stack_push(ctx, jsval_string(jsstr_addref(str)));
1126 /* ECMA-262 3rd Edition 7.8 */
1127 static HRESULT interp_regexp(script_ctx_t *ctx)
1129 jsstr_t *source = get_op_str(ctx, 0);
1130 const unsigned flags = get_op_uint(ctx, 1);
1131 jsdisp_t *regexp;
1132 HRESULT hres;
1134 TRACE("%s %x\n", debugstr_jsstr(source), flags);
1136 hres = create_regexp(ctx, source, flags, &regexp);
1137 if(FAILED(hres))
1138 return hres;
1140 return stack_push(ctx, jsval_obj(regexp));
1143 /* ECMA-262 3rd Edition 11.1.4 */
1144 static HRESULT interp_carray(script_ctx_t *ctx)
1146 const unsigned arg = get_op_uint(ctx, 0);
1147 jsdisp_t *array;
1148 jsval_t val;
1149 unsigned i;
1150 HRESULT hres;
1152 TRACE("%u\n", arg);
1154 hres = create_array(ctx, arg, &array);
1155 if(FAILED(hres))
1156 return hres;
1158 i = arg;
1159 while(i--) {
1160 val = stack_pop(ctx);
1161 hres = jsdisp_propput_idx(array, i, val);
1162 jsval_release(val);
1163 if(FAILED(hres)) {
1164 jsdisp_release(array);
1165 return hres;
1169 return stack_push(ctx, jsval_obj(array));
1172 /* ECMA-262 3rd Edition 11.1.5 */
1173 static HRESULT interp_new_obj(script_ctx_t *ctx)
1175 jsdisp_t *obj;
1176 HRESULT hres;
1178 TRACE("\n");
1180 hres = create_object(ctx, NULL, &obj);
1181 if(FAILED(hres))
1182 return hres;
1184 return stack_push(ctx, jsval_obj(obj));
1187 /* ECMA-262 3rd Edition 11.1.5 */
1188 static HRESULT interp_obj_prop(script_ctx_t *ctx)
1190 const BSTR name = get_op_bstr(ctx, 0);
1191 jsdisp_t *obj;
1192 jsval_t val;
1193 HRESULT hres;
1195 TRACE("%s\n", debugstr_w(name));
1197 val = stack_pop(ctx);
1199 assert(is_object_instance(stack_top(ctx)));
1200 obj = as_jsdisp(get_object(stack_top(ctx)));
1202 hres = jsdisp_propput_name(obj, name, val);
1203 jsval_release(val);
1204 return hres;
1207 /* ECMA-262 3rd Edition 11.11 */
1208 static HRESULT interp_cnd_nz(script_ctx_t *ctx)
1210 const unsigned arg = get_op_uint(ctx, 0);
1211 BOOL b;
1212 HRESULT hres;
1214 TRACE("\n");
1216 hres = to_boolean(stack_top(ctx), &b);
1217 if(FAILED(hres))
1218 return hres;
1220 if(b) {
1221 jmp_abs(ctx, arg);
1222 }else {
1223 stack_popn(ctx, 1);
1224 jmp_next(ctx);
1226 return S_OK;
1229 /* ECMA-262 3rd Edition 11.11 */
1230 static HRESULT interp_cnd_z(script_ctx_t *ctx)
1232 const unsigned arg = get_op_uint(ctx, 0);
1233 BOOL b;
1234 HRESULT hres;
1236 TRACE("\n");
1238 hres = to_boolean(stack_top(ctx), &b);
1239 if(FAILED(hres))
1240 return hres;
1242 if(b) {
1243 stack_popn(ctx, 1);
1244 jmp_next(ctx);
1245 }else {
1246 jmp_abs(ctx, arg);
1248 return S_OK;
1251 /* ECMA-262 3rd Edition 11.10 */
1252 static HRESULT interp_or(script_ctx_t *ctx)
1254 INT l, r;
1255 HRESULT hres;
1257 TRACE("\n");
1259 hres = stack_pop_int(ctx, &r);
1260 if(FAILED(hres))
1261 return hres;
1263 hres = stack_pop_int(ctx, &l);
1264 if(FAILED(hres))
1265 return hres;
1267 return stack_push(ctx, jsval_number(l|r));
1270 /* ECMA-262 3rd Edition 11.10 */
1271 static HRESULT interp_xor(script_ctx_t *ctx)
1273 INT l, r;
1274 HRESULT hres;
1276 TRACE("\n");
1278 hres = stack_pop_int(ctx, &r);
1279 if(FAILED(hres))
1280 return hres;
1282 hres = stack_pop_int(ctx, &l);
1283 if(FAILED(hres))
1284 return hres;
1286 return stack_push(ctx, jsval_number(l^r));
1289 /* ECMA-262 3rd Edition 11.10 */
1290 static HRESULT interp_and(script_ctx_t *ctx)
1292 INT l, r;
1293 HRESULT hres;
1295 TRACE("\n");
1297 hres = stack_pop_int(ctx, &r);
1298 if(FAILED(hres))
1299 return hres;
1301 hres = stack_pop_int(ctx, &l);
1302 if(FAILED(hres))
1303 return hres;
1305 return stack_push(ctx, jsval_number(l&r));
1308 /* ECMA-262 3rd Edition 11.8.6 */
1309 static HRESULT interp_instanceof(script_ctx_t *ctx)
1311 jsdisp_t *obj, *iter, *tmp = NULL;
1312 jsval_t prot, v;
1313 BOOL ret = FALSE;
1314 HRESULT hres;
1316 static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0};
1318 v = stack_pop(ctx);
1319 if(!is_object_instance(v) || !get_object(v)) {
1320 jsval_release(v);
1321 return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
1324 obj = iface_to_jsdisp((IUnknown*)get_object(v));
1325 IDispatch_Release(get_object(v));
1326 if(!obj) {
1327 FIXME("non-jsdisp objects not supported\n");
1328 return E_FAIL;
1331 if(is_class(obj, JSCLASS_FUNCTION)) {
1332 hres = jsdisp_propget_name(obj, prototypeW, &prot);
1333 }else {
1334 hres = throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
1336 jsdisp_release(obj);
1337 if(FAILED(hres))
1338 return hres;
1340 v = stack_pop(ctx);
1342 if(is_object_instance(prot)) {
1343 if(is_object_instance(v))
1344 tmp = iface_to_jsdisp((IUnknown*)get_object(v));
1345 for(iter = tmp; !ret && iter; iter = iter->prototype) {
1346 hres = disp_cmp(get_object(prot), to_disp(iter), &ret);
1347 if(FAILED(hres))
1348 break;
1351 if(tmp)
1352 jsdisp_release(tmp);
1353 }else {
1354 FIXME("prototype is not an object\n");
1355 hres = E_FAIL;
1358 jsval_release(prot);
1359 jsval_release(v);
1360 if(FAILED(hres))
1361 return hres;
1363 return stack_push(ctx, jsval_bool(ret));
1366 /* ECMA-262 3rd Edition 11.8.7 */
1367 static HRESULT interp_in(script_ctx_t *ctx)
1369 const WCHAR *str;
1370 jsstr_t *jsstr;
1371 jsval_t obj, v;
1372 DISPID id = 0;
1373 BOOL ret;
1374 HRESULT hres;
1376 TRACE("\n");
1378 obj = stack_pop(ctx);
1379 if(!is_object_instance(obj) || !get_object(obj)) {
1380 jsval_release(obj);
1381 return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
1384 v = stack_pop(ctx);
1385 hres = to_flat_string(ctx, v, &jsstr, &str);
1386 jsval_release(v);
1387 if(FAILED(hres)) {
1388 IDispatch_Release(get_object(obj));
1389 return hres;
1392 hres = disp_get_id(ctx, get_object(obj), str, NULL, 0, &id);
1393 IDispatch_Release(get_object(obj));
1394 jsstr_release(jsstr);
1395 if(SUCCEEDED(hres))
1396 ret = TRUE;
1397 else if(hres == DISP_E_UNKNOWNNAME)
1398 ret = FALSE;
1399 else
1400 return hres;
1402 return stack_push(ctx, jsval_bool(ret));
1405 /* ECMA-262 3rd Edition 11.6.1 */
1406 static HRESULT add_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, jsval_t *ret)
1408 jsval_t r, l;
1409 HRESULT hres;
1411 hres = to_primitive(ctx, lval, &l, NO_HINT);
1412 if(FAILED(hres))
1413 return hres;
1415 hres = to_primitive(ctx, rval, &r, NO_HINT);
1416 if(FAILED(hres)) {
1417 jsval_release(l);
1418 return hres;
1421 if(is_string(l) || is_string(r)) {
1422 jsstr_t *lstr, *rstr = NULL;
1424 hres = to_string(ctx, l, &lstr);
1425 if(SUCCEEDED(hres))
1426 hres = to_string(ctx, r, &rstr);
1428 if(SUCCEEDED(hres)) {
1429 jsstr_t *ret_str;
1431 ret_str = jsstr_concat(lstr, rstr);
1432 if(ret_str)
1433 *ret = jsval_string(ret_str);
1434 else
1435 hres = E_OUTOFMEMORY;
1438 jsstr_release(lstr);
1439 if(rstr)
1440 jsstr_release(rstr);
1441 }else {
1442 double nl, nr;
1444 hres = to_number(ctx, l, &nl);
1445 if(SUCCEEDED(hres)) {
1446 hres = to_number(ctx, r, &nr);
1447 if(SUCCEEDED(hres))
1448 *ret = jsval_number(nl+nr);
1452 jsval_release(r);
1453 jsval_release(l);
1454 return hres;
1457 /* ECMA-262 3rd Edition 11.6.1 */
1458 static HRESULT interp_add(script_ctx_t *ctx)
1460 jsval_t l, r, ret;
1461 HRESULT hres;
1463 r = stack_pop(ctx);
1464 l = stack_pop(ctx);
1466 TRACE("%s + %s\n", debugstr_jsval(l), debugstr_jsval(r));
1468 hres = add_eval(ctx, l, r, &ret);
1469 jsval_release(l);
1470 jsval_release(r);
1471 if(FAILED(hres))
1472 return hres;
1474 return stack_push(ctx, ret);
1477 /* ECMA-262 3rd Edition 11.6.2 */
1478 static HRESULT interp_sub(script_ctx_t *ctx)
1480 double l, r;
1481 HRESULT hres;
1483 TRACE("\n");
1485 hres = stack_pop_number(ctx, &r);
1486 if(FAILED(hres))
1487 return hres;
1489 hres = stack_pop_number(ctx, &l);
1490 if(FAILED(hres))
1491 return hres;
1493 return stack_push(ctx, jsval_number(l-r));
1496 /* ECMA-262 3rd Edition 11.5.1 */
1497 static HRESULT interp_mul(script_ctx_t *ctx)
1499 double l, r;
1500 HRESULT hres;
1502 TRACE("\n");
1504 hres = stack_pop_number(ctx, &r);
1505 if(FAILED(hres))
1506 return hres;
1508 hres = stack_pop_number(ctx, &l);
1509 if(FAILED(hres))
1510 return hres;
1512 return stack_push(ctx, jsval_number(l*r));
1515 /* ECMA-262 3rd Edition 11.5.2 */
1516 static HRESULT interp_div(script_ctx_t *ctx)
1518 double l, r;
1519 HRESULT hres;
1521 TRACE("\n");
1523 hres = stack_pop_number(ctx, &r);
1524 if(FAILED(hres))
1525 return hres;
1527 hres = stack_pop_number(ctx, &l);
1528 if(FAILED(hres))
1529 return hres;
1531 return stack_push(ctx, jsval_number(l/r));
1534 /* ECMA-262 3rd Edition 11.5.3 */
1535 static HRESULT interp_mod(script_ctx_t *ctx)
1537 double l, r;
1538 HRESULT hres;
1540 TRACE("\n");
1542 hres = stack_pop_number(ctx, &r);
1543 if(FAILED(hres))
1544 return hres;
1546 hres = stack_pop_number(ctx, &l);
1547 if(FAILED(hres))
1548 return hres;
1550 return stack_push(ctx, jsval_number(fmod(l, r)));
1553 /* ECMA-262 3rd Edition 11.4.2 */
1554 static HRESULT interp_delete(script_ctx_t *ctx)
1556 jsval_t objv, namev;
1557 IDispatch *obj;
1558 jsstr_t *name;
1559 BOOL ret;
1560 HRESULT hres;
1562 TRACE("\n");
1564 namev = stack_pop(ctx);
1565 objv = stack_pop(ctx);
1567 hres = to_object(ctx, objv, &obj);
1568 jsval_release(objv);
1569 if(FAILED(hres)) {
1570 jsval_release(namev);
1571 return hres;
1574 hres = to_string(ctx, namev, &name);
1575 jsval_release(namev);
1576 if(FAILED(hres)) {
1577 IDispatch_Release(obj);
1578 return hres;
1581 hres = disp_delete_name(ctx, obj, name, &ret);
1582 IDispatch_Release(obj);
1583 jsstr_release(name);
1584 if(FAILED(hres))
1585 return hres;
1587 return stack_push(ctx, jsval_bool(ret));
1590 /* ECMA-262 3rd Edition 11.4.2 */
1591 static HRESULT interp_delete_ident(script_ctx_t *ctx)
1593 const BSTR arg = get_op_bstr(ctx, 0);
1594 exprval_t exprval;
1595 BOOL ret;
1596 HRESULT hres;
1598 TRACE("%s\n", debugstr_w(arg));
1600 hres = identifier_eval(ctx, arg, &exprval);
1601 if(FAILED(hres))
1602 return hres;
1604 switch(exprval.type) {
1605 case EXPRVAL_IDREF:
1606 hres = disp_delete(exprval.u.idref.disp, exprval.u.idref.id, &ret);
1607 IDispatch_Release(exprval.u.idref.disp);
1608 if(FAILED(hres))
1609 return hres;
1610 break;
1611 case EXPRVAL_INVALID:
1612 ret = TRUE;
1613 break;
1614 default:
1615 FIXME("Unsupported exprval\n");
1616 exprval_release(&exprval);
1617 return E_NOTIMPL;
1621 return stack_push(ctx, jsval_bool(ret));
1624 /* ECMA-262 3rd Edition 11.4.2 */
1625 static HRESULT interp_void(script_ctx_t *ctx)
1627 TRACE("\n");
1629 stack_popn(ctx, 1);
1630 return stack_push(ctx, jsval_undefined());
1633 /* ECMA-262 3rd Edition 11.4.3 */
1634 static HRESULT typeof_string(jsval_t v, const WCHAR **ret)
1636 switch(jsval_type(v)) {
1637 case JSV_UNDEFINED:
1638 *ret = undefinedW;
1639 break;
1640 case JSV_NULL:
1641 *ret = objectW;
1642 break;
1643 case JSV_OBJECT: {
1644 jsdisp_t *dispex;
1646 if(get_object(v) && (dispex = iface_to_jsdisp((IUnknown*)get_object(v)))) {
1647 *ret = is_class(dispex, JSCLASS_FUNCTION) ? functionW : objectW;
1648 jsdisp_release(dispex);
1649 }else {
1650 *ret = objectW;
1652 break;
1654 case JSV_STRING:
1655 *ret = stringW;
1656 break;
1657 case JSV_NUMBER:
1658 *ret = numberW;
1659 break;
1660 case JSV_BOOL:
1661 *ret = booleanW;
1662 break;
1663 case JSV_VARIANT:
1664 FIXME("unhandled variant %s\n", debugstr_variant(get_variant(v)));
1665 return E_NOTIMPL;
1668 return S_OK;
1671 /* ECMA-262 3rd Edition 11.4.3 */
1672 static HRESULT interp_typeofid(script_ctx_t *ctx)
1674 const WCHAR *ret;
1675 IDispatch *obj;
1676 jsval_t v;
1677 DISPID id;
1678 HRESULT hres;
1680 TRACE("\n");
1682 obj = stack_pop_objid(ctx, &id);
1683 if(!obj)
1684 return stack_push(ctx, jsval_string(jsstr_undefined()));
1686 hres = disp_propget(ctx, obj, id, &v);
1687 IDispatch_Release(obj);
1688 if(FAILED(hres))
1689 return stack_push_string(ctx, unknownW);
1691 hres = typeof_string(v, &ret);
1692 jsval_release(v);
1693 if(FAILED(hres))
1694 return hres;
1696 return stack_push_string(ctx, ret);
1699 /* ECMA-262 3rd Edition 11.4.3 */
1700 static HRESULT interp_typeofident(script_ctx_t *ctx)
1702 const BSTR arg = get_op_bstr(ctx, 0);
1703 exprval_t exprval;
1704 const WCHAR *ret;
1705 jsval_t v;
1706 HRESULT hres;
1708 TRACE("%s\n", debugstr_w(arg));
1710 hres = identifier_eval(ctx, arg, &exprval);
1711 if(FAILED(hres))
1712 return hres;
1714 if(exprval.type == EXPRVAL_INVALID) {
1715 hres = stack_push(ctx, jsval_string(jsstr_undefined()));
1716 exprval_release(&exprval);
1717 return hres;
1720 hres = exprval_to_value(ctx, &exprval, &v);
1721 exprval_release(&exprval);
1722 if(FAILED(hres))
1723 return hres;
1725 hres = typeof_string(v, &ret);
1726 jsval_release(v);
1727 if(FAILED(hres))
1728 return hres;
1730 return stack_push_string(ctx, ret);
1733 /* ECMA-262 3rd Edition 11.4.3 */
1734 static HRESULT interp_typeof(script_ctx_t *ctx)
1736 const WCHAR *ret;
1737 jsval_t v;
1738 HRESULT hres;
1740 TRACE("\n");
1742 v = stack_pop(ctx);
1743 hres = typeof_string(v, &ret);
1744 jsval_release(v);
1745 if(FAILED(hres))
1746 return hres;
1748 return stack_push_string(ctx, ret);
1751 /* ECMA-262 3rd Edition 11.4.7 */
1752 static HRESULT interp_minus(script_ctx_t *ctx)
1754 double n;
1755 HRESULT hres;
1757 TRACE("\n");
1759 hres = stack_pop_number(ctx, &n);
1760 if(FAILED(hres))
1761 return hres;
1763 return stack_push(ctx, jsval_number(-n));
1766 /* ECMA-262 3rd Edition 11.4.6 */
1767 static HRESULT interp_tonum(script_ctx_t *ctx)
1769 jsval_t v;
1770 double n;
1771 HRESULT hres;
1773 TRACE("\n");
1775 v = stack_pop(ctx);
1776 hres = to_number(ctx, v, &n);
1777 jsval_release(v);
1778 if(FAILED(hres))
1779 return hres;
1781 return stack_push(ctx, jsval_number(n));
1784 /* ECMA-262 3rd Edition 11.3.1 */
1785 static HRESULT interp_postinc(script_ctx_t *ctx)
1787 const int arg = get_op_int(ctx, 0);
1788 IDispatch *obj;
1789 DISPID id;
1790 jsval_t v;
1791 HRESULT hres;
1793 TRACE("%d\n", arg);
1795 obj = stack_pop_objid(ctx, &id);
1796 if(!obj)
1797 return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
1799 hres = disp_propget(ctx, obj, id, &v);
1800 if(SUCCEEDED(hres)) {
1801 double n;
1803 hres = to_number(ctx, v, &n);
1804 if(SUCCEEDED(hres))
1805 hres = disp_propput(ctx, obj, id, jsval_number(n+(double)arg));
1806 if(FAILED(hres))
1807 jsval_release(v);
1809 IDispatch_Release(obj);
1810 if(FAILED(hres))
1811 return hres;
1813 return stack_push(ctx, v);
1816 /* ECMA-262 3rd Edition 11.4.4, 11.4.5 */
1817 static HRESULT interp_preinc(script_ctx_t *ctx)
1819 const int arg = get_op_int(ctx, 0);
1820 IDispatch *obj;
1821 double ret;
1822 DISPID id;
1823 jsval_t v;
1824 HRESULT hres;
1826 TRACE("%d\n", arg);
1828 obj = stack_pop_objid(ctx, &id);
1829 if(!obj)
1830 return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
1832 hres = disp_propget(ctx, obj, id, &v);
1833 if(SUCCEEDED(hres)) {
1834 double n;
1836 hres = to_number(ctx, v, &n);
1837 jsval_release(v);
1838 if(SUCCEEDED(hres)) {
1839 ret = n+(double)arg;
1840 hres = disp_propput(ctx, obj, id, jsval_number(ret));
1843 IDispatch_Release(obj);
1844 if(FAILED(hres))
1845 return hres;
1847 return stack_push(ctx, jsval_number(ret));
1850 /* ECMA-262 3rd Edition 11.9.3 */
1851 static HRESULT equal_values(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL *ret)
1853 if(jsval_type(lval) == jsval_type(rval) || (is_number(lval) && is_number(rval)))
1854 return equal2_values(lval, rval, ret);
1856 /* FIXME: NULL disps should be handled in more general way */
1857 if(is_object_instance(lval) && !get_object(lval))
1858 return equal_values(ctx, jsval_null(), rval, ret);
1859 if(is_object_instance(rval) && !get_object(rval))
1860 return equal_values(ctx, lval, jsval_null(), ret);
1862 if((is_null(lval) && is_undefined(rval)) || (is_undefined(lval) && is_null(rval))) {
1863 *ret = TRUE;
1864 return S_OK;
1867 if(is_string(lval) && is_number(rval)) {
1868 double n;
1869 HRESULT hres;
1871 hres = to_number(ctx, lval, &n);
1872 if(FAILED(hres))
1873 return hres;
1875 /* FIXME: optimize */
1876 return equal_values(ctx, jsval_number(n), rval, ret);
1879 if(is_string(rval) && is_number(lval)) {
1880 double n;
1881 HRESULT hres;
1883 hres = to_number(ctx, rval, &n);
1884 if(FAILED(hres))
1885 return hres;
1887 /* FIXME: optimize */
1888 return equal_values(ctx, lval, jsval_number(n), ret);
1891 if(is_bool(rval))
1892 return equal_values(ctx, lval, jsval_number(get_bool(rval) ? 1 : 0), ret);
1894 if(is_bool(lval))
1895 return equal_values(ctx, jsval_number(get_bool(lval) ? 1 : 0), rval, ret);
1898 if(is_object_instance(rval) && (is_string(lval) || is_number(lval))) {
1899 jsval_t prim;
1900 HRESULT hres;
1902 hres = to_primitive(ctx, rval, &prim, NO_HINT);
1903 if(FAILED(hres))
1904 return hres;
1906 hres = equal_values(ctx, lval, prim, ret);
1907 jsval_release(prim);
1908 return hres;
1912 if(is_object_instance(lval) && (is_string(rval) || is_number(rval))) {
1913 jsval_t prim;
1914 HRESULT hres;
1916 hres = to_primitive(ctx, lval, &prim, NO_HINT);
1917 if(FAILED(hres))
1918 return hres;
1920 hres = equal_values(ctx, prim, rval, ret);
1921 jsval_release(prim);
1922 return hres;
1926 *ret = FALSE;
1927 return S_OK;
1930 /* ECMA-262 3rd Edition 11.9.1 */
1931 static HRESULT interp_eq(script_ctx_t *ctx)
1933 jsval_t l, r;
1934 BOOL b;
1935 HRESULT hres;
1937 r = stack_pop(ctx);
1938 l = stack_pop(ctx);
1940 TRACE("%s == %s\n", debugstr_jsval(l), debugstr_jsval(r));
1942 hres = equal_values(ctx, l, r, &b);
1943 jsval_release(l);
1944 jsval_release(r);
1945 if(FAILED(hres))
1946 return hres;
1948 return stack_push(ctx, jsval_bool(b));
1951 /* ECMA-262 3rd Edition 11.9.2 */
1952 static HRESULT interp_neq(script_ctx_t *ctx)
1954 jsval_t l, r;
1955 BOOL b;
1956 HRESULT hres;
1958 r = stack_pop(ctx);
1959 l = stack_pop(ctx);
1961 TRACE("%s != %s\n", debugstr_jsval(l), debugstr_jsval(r));
1963 hres = equal_values(ctx, l, r, &b);
1964 jsval_release(l);
1965 jsval_release(r);
1966 if(FAILED(hres))
1967 return hres;
1969 return stack_push(ctx, jsval_bool(!b));
1972 /* ECMA-262 3rd Edition 11.9.4 */
1973 static HRESULT interp_eq2(script_ctx_t *ctx)
1975 jsval_t l, r;
1976 BOOL b;
1977 HRESULT hres;
1979 r = stack_pop(ctx);
1980 l = stack_pop(ctx);
1982 TRACE("%s === %s\n", debugstr_jsval(l), debugstr_jsval(r));
1984 hres = equal2_values(r, l, &b);
1985 jsval_release(l);
1986 jsval_release(r);
1987 if(FAILED(hres))
1988 return hres;
1990 return stack_push(ctx, jsval_bool(b));
1993 /* ECMA-262 3rd Edition 11.9.5 */
1994 static HRESULT interp_neq2(script_ctx_t *ctx)
1996 jsval_t l, r;
1997 BOOL b;
1998 HRESULT hres;
2000 TRACE("\n");
2002 r = stack_pop(ctx);
2003 l = stack_pop(ctx);
2005 hres = equal2_values(r, l, &b);
2006 jsval_release(l);
2007 jsval_release(r);
2008 if(FAILED(hres))
2009 return hres;
2011 return stack_push(ctx, jsval_bool(!b));
2014 /* ECMA-262 3rd Edition 11.8.5 */
2015 static HRESULT less_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL greater, BOOL *ret)
2017 double ln, rn;
2018 jsval_t l, r;
2019 HRESULT hres;
2021 hres = to_primitive(ctx, lval, &l, NO_HINT);
2022 if(FAILED(hres))
2023 return hres;
2025 hres = to_primitive(ctx, rval, &r, NO_HINT);
2026 if(FAILED(hres)) {
2027 jsval_release(l);
2028 return hres;
2031 if(is_string(l) && is_string(r)) {
2032 *ret = (jsstr_cmp(get_string(l), get_string(r)) < 0) ^ greater;
2033 jsstr_release(get_string(l));
2034 jsstr_release(get_string(r));
2035 return S_OK;
2038 hres = to_number(ctx, l, &ln);
2039 jsval_release(l);
2040 if(SUCCEEDED(hres))
2041 hres = to_number(ctx, r, &rn);
2042 jsval_release(r);
2043 if(FAILED(hres))
2044 return hres;
2046 *ret = !isnan(ln) && !isnan(rn) && ((ln < rn) ^ greater);
2047 return S_OK;
2050 /* ECMA-262 3rd Edition 11.8.1 */
2051 static HRESULT interp_lt(script_ctx_t *ctx)
2053 jsval_t l, r;
2054 BOOL b;
2055 HRESULT hres;
2057 r = stack_pop(ctx);
2058 l = stack_pop(ctx);
2060 TRACE("%s < %s\n", debugstr_jsval(l), debugstr_jsval(r));
2062 hres = less_eval(ctx, l, r, FALSE, &b);
2063 jsval_release(l);
2064 jsval_release(r);
2065 if(FAILED(hres))
2066 return hres;
2068 return stack_push(ctx, jsval_bool(b));
2071 /* ECMA-262 3rd Edition 11.8.1 */
2072 static HRESULT interp_lteq(script_ctx_t *ctx)
2074 jsval_t l, r;
2075 BOOL b;
2076 HRESULT hres;
2078 r = stack_pop(ctx);
2079 l = stack_pop(ctx);
2081 TRACE("%s <= %s\n", debugstr_jsval(l), debugstr_jsval(r));
2083 hres = less_eval(ctx, r, l, TRUE, &b);
2084 jsval_release(l);
2085 jsval_release(r);
2086 if(FAILED(hres))
2087 return hres;
2089 return stack_push(ctx, jsval_bool(b));
2092 /* ECMA-262 3rd Edition 11.8.2 */
2093 static HRESULT interp_gt(script_ctx_t *ctx)
2095 jsval_t l, r;
2096 BOOL b;
2097 HRESULT hres;
2099 r = stack_pop(ctx);
2100 l = stack_pop(ctx);
2102 TRACE("%s > %s\n", debugstr_jsval(l), debugstr_jsval(r));
2104 hres = less_eval(ctx, r, l, FALSE, &b);
2105 jsval_release(l);
2106 jsval_release(r);
2107 if(FAILED(hres))
2108 return hres;
2110 return stack_push(ctx, jsval_bool(b));
2113 /* ECMA-262 3rd Edition 11.8.4 */
2114 static HRESULT interp_gteq(script_ctx_t *ctx)
2116 jsval_t l, r;
2117 BOOL b;
2118 HRESULT hres;
2120 r = stack_pop(ctx);
2121 l = stack_pop(ctx);
2123 TRACE("%s >= %s\n", debugstr_jsval(l), debugstr_jsval(r));
2125 hres = less_eval(ctx, l, r, TRUE, &b);
2126 jsval_release(l);
2127 jsval_release(r);
2128 if(FAILED(hres))
2129 return hres;
2131 return stack_push(ctx, jsval_bool(b));
2134 /* ECMA-262 3rd Edition 11.4.8 */
2135 static HRESULT interp_bneg(script_ctx_t *ctx)
2137 jsval_t v;
2138 INT i;
2139 HRESULT hres;
2141 TRACE("\n");
2143 v = stack_pop(ctx);
2144 hres = to_int32(ctx, v, &i);
2145 jsval_release(v);
2146 if(FAILED(hres))
2147 return hres;
2149 return stack_push(ctx, jsval_number(~i));
2152 /* ECMA-262 3rd Edition 11.4.9 */
2153 static HRESULT interp_neg(script_ctx_t *ctx)
2155 jsval_t v;
2156 BOOL b;
2157 HRESULT hres;
2159 TRACE("\n");
2161 v = stack_pop(ctx);
2162 hres = to_boolean(v, &b);
2163 jsval_release(v);
2164 if(FAILED(hres))
2165 return hres;
2167 return stack_push(ctx, jsval_bool(!b));
2170 /* ECMA-262 3rd Edition 11.7.1 */
2171 static HRESULT interp_lshift(script_ctx_t *ctx)
2173 DWORD r;
2174 INT l;
2175 HRESULT hres;
2177 hres = stack_pop_uint(ctx, &r);
2178 if(FAILED(hres))
2179 return hres;
2181 hres = stack_pop_int(ctx, &l);
2182 if(FAILED(hres))
2183 return hres;
2185 return stack_push(ctx, jsval_number(l << (r&0x1f)));
2188 /* ECMA-262 3rd Edition 11.7.2 */
2189 static HRESULT interp_rshift(script_ctx_t *ctx)
2191 DWORD r;
2192 INT l;
2193 HRESULT hres;
2195 hres = stack_pop_uint(ctx, &r);
2196 if(FAILED(hres))
2197 return hres;
2199 hres = stack_pop_int(ctx, &l);
2200 if(FAILED(hres))
2201 return hres;
2203 return stack_push(ctx, jsval_number(l >> (r&0x1f)));
2206 /* ECMA-262 3rd Edition 11.7.3 */
2207 static HRESULT interp_rshift2(script_ctx_t *ctx)
2209 DWORD r, l;
2210 HRESULT hres;
2212 hres = stack_pop_uint(ctx, &r);
2213 if(FAILED(hres))
2214 return hres;
2216 hres = stack_pop_uint(ctx, &l);
2217 if(FAILED(hres))
2218 return hres;
2220 return stack_push(ctx, jsval_number(l >> (r&0x1f)));
2223 /* ECMA-262 3rd Edition 11.13.1 */
2224 static HRESULT interp_assign(script_ctx_t *ctx)
2226 IDispatch *disp;
2227 DISPID id;
2228 jsval_t v;
2229 HRESULT hres;
2231 TRACE("\n");
2233 v = stack_pop(ctx);
2235 disp = stack_pop_objid(ctx, &id);
2236 if(!disp) {
2237 jsval_release(v);
2238 return throw_reference_error(ctx, JS_E_ILLEGAL_ASSIGN, NULL);
2241 hres = disp_propput(ctx, disp, id, v);
2242 IDispatch_Release(disp);
2243 if(FAILED(hres)) {
2244 jsval_release(v);
2245 return hres;
2248 return stack_push(ctx, v);
2251 /* JScript extension */
2252 static HRESULT interp_assign_call(script_ctx_t *ctx)
2254 const unsigned argc = get_op_uint(ctx, 0);
2255 IDispatch *disp;
2256 jsval_t v;
2257 DISPID id;
2258 HRESULT hres;
2260 TRACE("%u\n", argc);
2262 disp = stack_topn_objid(ctx, argc+1, &id);
2263 if(!disp)
2264 return throw_reference_error(ctx, JS_E_ILLEGAL_ASSIGN, NULL);
2266 hres = disp_call(ctx, disp, id, DISPATCH_PROPERTYPUT, argc+1, stack_args(ctx, argc+1), NULL);
2267 if(FAILED(hres))
2268 return hres;
2270 v = stack_pop(ctx);
2271 stack_popn(ctx, argc+2);
2272 return stack_push(ctx, v);
2275 static HRESULT interp_undefined(script_ctx_t *ctx)
2277 TRACE("\n");
2279 return stack_push(ctx, jsval_undefined());
2282 static HRESULT interp_jmp(script_ctx_t *ctx)
2284 const unsigned arg = get_op_uint(ctx, 0);
2286 TRACE("%u\n", arg);
2288 jmp_abs(ctx, arg);
2289 return S_OK;
2292 static HRESULT interp_jmp_z(script_ctx_t *ctx)
2294 const unsigned arg = get_op_uint(ctx, 0);
2295 BOOL b;
2296 jsval_t v;
2297 HRESULT hres;
2299 TRACE("\n");
2301 v = stack_pop(ctx);
2302 hres = to_boolean(v, &b);
2303 jsval_release(v);
2304 if(FAILED(hres))
2305 return hres;
2307 if(b)
2308 jmp_next(ctx);
2309 else
2310 jmp_abs(ctx, arg);
2311 return S_OK;
2314 static HRESULT interp_pop(script_ctx_t *ctx)
2316 const unsigned arg = get_op_uint(ctx, 0);
2318 TRACE("%u\n", arg);
2320 stack_popn(ctx, arg);
2321 return S_OK;
2324 static HRESULT interp_ret(script_ctx_t *ctx)
2326 const unsigned clear_ret = get_op_uint(ctx, 0);
2327 call_frame_t *frame = ctx->call_ctx;
2329 TRACE("\n");
2331 if(clear_ret)
2332 jsval_release(steal_ret(frame));
2334 if((frame->flags & EXEC_CONSTRUCTOR) && !is_object_instance(frame->ret)) {
2335 jsval_release(frame->ret);
2336 IDispatch_AddRef(frame->this_obj);
2337 frame->ret = jsval_disp(frame->this_obj);
2340 jmp_abs(ctx, -1);
2341 return S_OK;
2344 static HRESULT interp_setret(script_ctx_t *ctx)
2346 call_frame_t *frame = ctx->call_ctx;
2348 TRACE("\n");
2350 jsval_release(frame->ret);
2351 frame->ret = stack_pop(ctx);
2352 return S_OK;
2355 static HRESULT interp_push_ret(script_ctx_t *ctx)
2357 call_frame_t *frame = ctx->call_ctx;
2358 HRESULT hres;
2360 TRACE("\n");
2362 hres = stack_push(ctx, frame->ret);
2363 if(SUCCEEDED(hres))
2364 frame->ret = jsval_undefined();
2365 return hres;
2368 typedef HRESULT (*op_func_t)(script_ctx_t*);
2370 static const op_func_t op_funcs[] = {
2371 #define X(x,a,b,c) interp_##x,
2372 OP_LIST
2373 #undef X
2376 static const unsigned op_move[] = {
2377 #define X(a,x,b,c) x,
2378 OP_LIST
2379 #undef X
2382 static void release_call_frame(call_frame_t *frame)
2384 if(frame->arguments_obj) {
2385 /* Reset arguments value to cut the reference cycle. Note that since all activation contexts have
2386 * their own arguments property, it's impossible to use prototype's one during name lookup */
2387 static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0};
2388 jsdisp_propput_name(frame->variable_obj, argumentsW, jsval_undefined());
2389 jsdisp_release(frame->arguments_obj);
2391 if(frame->function_instance)
2392 jsdisp_release(frame->function_instance);
2393 if(frame->variable_obj)
2394 jsdisp_release(frame->variable_obj);
2395 if(frame->this_obj)
2396 IDispatch_Release(frame->this_obj);
2397 if(frame->scope)
2398 scope_release(frame->scope);
2399 jsval_release(frame->ret);
2400 release_bytecode(frame->bytecode);
2401 heap_free(frame);
2404 static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres)
2406 except_frame_t *except_frame;
2407 call_frame_t *frame;
2408 jsval_t except_val;
2409 BSTR ident;
2410 HRESULT hres;
2412 for(frame = ctx->call_ctx; !frame->except_frame; frame = ctx->call_ctx) {
2413 DWORD flags;
2415 while(frame->scope != frame->base_scope)
2416 scope_pop(&frame->scope);
2418 stack_popn(ctx, ctx->stack_top-frame->stack_base);
2420 ctx->call_ctx = frame->prev_frame;
2421 flags = frame->flags;
2422 release_call_frame(frame);
2423 if(!(flags & EXEC_RETURN_TO_INTERP))
2424 return exception_hres;
2427 except_frame = frame->except_frame;
2428 frame->except_frame = except_frame->next;
2430 assert(except_frame->stack_top <= ctx->stack_top);
2431 stack_popn(ctx, ctx->stack_top - except_frame->stack_top);
2433 while(except_frame->scope != frame->scope)
2434 scope_pop(&frame->scope);
2436 frame->ip = except_frame->catch_off;
2438 except_val = ctx->ei.val;
2439 ctx->ei.val = jsval_undefined();
2440 clear_ei(ctx);
2442 ident = except_frame->ident;
2443 heap_free(except_frame);
2445 if(ident) {
2446 jsdisp_t *scope_obj;
2448 hres = create_dispex(ctx, NULL, NULL, &scope_obj);
2449 if(SUCCEEDED(hres)) {
2450 hres = jsdisp_propput_name(scope_obj, ident, except_val);
2451 if(FAILED(hres))
2452 jsdisp_release(scope_obj);
2454 jsval_release(except_val);
2455 if(FAILED(hres))
2456 return hres;
2458 hres = scope_push(frame->scope, scope_obj, to_disp(scope_obj), &frame->scope);
2459 jsdisp_release(scope_obj);
2460 }else {
2461 hres = stack_push(ctx, except_val);
2462 if(FAILED(hres))
2463 return hres;
2465 hres = stack_push(ctx, jsval_bool(FALSE));
2468 return hres;
2471 static HRESULT enter_bytecode(script_ctx_t *ctx, jsval_t *r)
2473 call_frame_t *frame;
2474 jsop_t op;
2475 HRESULT hres = S_OK;
2477 TRACE("\n");
2479 while(1) {
2480 frame = ctx->call_ctx;
2481 op = frame->bytecode->instrs[frame->ip].op;
2482 hres = op_funcs[op](ctx);
2483 if(FAILED(hres)) {
2484 TRACE("EXCEPTION %08x\n", hres);
2486 hres = unwind_exception(ctx, hres);
2487 if(FAILED(hres))
2488 return hres;
2489 }else if(frame->ip == -1) {
2490 const DWORD return_to_interp = frame->flags & EXEC_RETURN_TO_INTERP;
2492 assert(ctx->stack_top == frame->stack_base);
2493 assert(frame->scope == frame->base_scope);
2495 ctx->call_ctx = frame->prev_frame;
2496 if(return_to_interp) {
2497 clear_ret(ctx->call_ctx);
2498 ctx->call_ctx->ret = steal_ret(frame);
2499 }else if(r) {
2500 *r = steal_ret(frame);
2502 release_call_frame(frame);
2503 if(!return_to_interp)
2504 break;
2505 }else {
2506 frame->ip += op_move[op];
2510 return S_OK;
2513 static HRESULT bind_event_target(script_ctx_t *ctx, function_code_t *func, jsdisp_t *func_obj)
2515 IBindEventHandler *target;
2516 exprval_t exprval;
2517 IDispatch *disp;
2518 jsval_t v;
2519 HRESULT hres;
2521 hres = identifier_eval(ctx, func->event_target, &exprval);
2522 if(FAILED(hres))
2523 return hres;
2525 hres = exprval_to_value(ctx, &exprval, &v);
2526 exprval_release(&exprval);
2527 if(FAILED(hres))
2528 return hres;
2530 if(!is_object_instance(v)) {
2531 FIXME("Can't bind to %s\n", debugstr_jsval(v));
2532 jsval_release(v);
2535 disp = get_object(v);
2536 hres = IDispatch_QueryInterface(disp, &IID_IBindEventHandler, (void**)&target);
2537 if(SUCCEEDED(hres)) {
2538 hres = IBindEventHandler_BindHandler(target, func->name, (IDispatch*)&func_obj->IDispatchEx_iface);
2539 IBindEventHandler_Release(target);
2540 if(FAILED(hres))
2541 WARN("BindEvent failed: %08x\n", hres);
2542 }else {
2543 FIXME("No IBindEventHandler, not yet supported binding\n");
2546 IDispatch_Release(disp);
2547 return hres;
2550 HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, function_code_t *function, scope_chain_t *scope,
2551 IDispatch *this_obj, jsdisp_t *function_instance, jsdisp_t *variable_obj, jsdisp_t *arguments_obj, jsval_t *r)
2553 call_frame_t *frame;
2554 unsigned i;
2555 HRESULT hres;
2557 for(i = 0; i < function->func_cnt; i++) {
2558 jsdisp_t *func_obj;
2560 if(!function->funcs[i].name)
2561 continue;
2563 hres = create_source_function(ctx, bytecode, function->funcs+i, scope, &func_obj);
2564 if(FAILED(hres))
2565 return hres;
2567 if(function->funcs[i].event_target)
2568 hres = bind_event_target(ctx, function->funcs+i, func_obj);
2569 else
2570 hres = jsdisp_propput_name(variable_obj, function->funcs[i].name, jsval_obj(func_obj));
2571 jsdisp_release(func_obj);
2572 if(FAILED(hres))
2573 return hres;
2576 for(i=0; i < function->var_cnt; i++) {
2577 if(!(flags & EXEC_GLOBAL) || !lookup_global_members(ctx, function->variables[i], NULL)) {
2578 DISPID id = 0;
2580 hres = jsdisp_get_id(variable_obj, function->variables[i], fdexNameEnsure, &id);
2581 if(FAILED(hres))
2582 return hres;
2586 /* ECMA-262 3rd Edition 11.2.3.7 */
2587 if(this_obj) {
2588 jsdisp_t *jsthis;
2590 jsthis = iface_to_jsdisp((IUnknown*)this_obj);
2591 if(jsthis) {
2592 if(jsthis->builtin_info->class == JSCLASS_GLOBAL || jsthis->builtin_info->class == JSCLASS_NONE)
2593 this_obj = NULL;
2594 jsdisp_release(jsthis);
2598 frame = heap_alloc_zero(sizeof(*frame));
2599 if(!frame)
2600 return E_OUTOFMEMORY;
2602 frame->bytecode = bytecode_addref(bytecode);
2603 frame->function = function;
2604 frame->ip = function->instr_off;
2605 frame->stack_base = ctx->stack_top;
2606 frame->ret = jsval_undefined();
2607 if(scope)
2608 frame->base_scope = frame->scope = scope_addref(scope);
2610 if(this_obj)
2611 frame->this_obj = this_obj;
2612 else if(ctx->host_global)
2613 frame->this_obj = ctx->host_global;
2614 else
2615 frame->this_obj = to_disp(ctx->global);
2616 IDispatch_AddRef(frame->this_obj);
2618 if(function_instance)
2619 frame->function_instance = jsdisp_addref(function_instance);
2620 if(arguments_obj)
2621 frame->arguments_obj = jsdisp_addref(arguments_obj);
2623 frame->flags = flags;
2624 frame->variable_obj = jsdisp_addref(variable_obj);
2626 frame->prev_frame = ctx->call_ctx;
2627 ctx->call_ctx = frame;
2629 if(flags & EXEC_RETURN_TO_INTERP) {
2631 * We're called directly from interpreter, so we may just setup call frame and return.
2632 * Already running interpreter will take care of execution.
2634 if(r)
2635 *r = jsval_undefined();
2636 return S_OK;
2639 return enter_bytecode(ctx, r);