jscript: Add function name to its scope chain in ES5 mode.
[wine/zf.git] / dlls / jscript / engine.c
blobf3d9d694b2aed379ab81b2cf8524553e777f3226
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
20 #include <math.h>
21 #include <assert.h>
23 #include "jscript.h"
24 #include "engine.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
30 struct _except_frame_t {
31 unsigned stack_top;
32 scope_chain_t *scope;
33 unsigned catch_off;
34 unsigned finally_off;
36 except_frame_t *next;
39 typedef struct {
40 enum {
41 EXPRVAL_JSVAL,
42 EXPRVAL_IDREF,
43 EXPRVAL_STACK_REF,
44 EXPRVAL_INVALID
45 } type;
46 union {
47 jsval_t val;
48 struct {
49 IDispatch *disp;
50 DISPID id;
51 } idref;
52 unsigned off;
53 HRESULT hres;
54 } u;
55 } exprval_t;
57 static const size_t stack_size = 0x40000;
59 static HRESULT stack_push(script_ctx_t *ctx, jsval_t v)
61 if(ctx->stack_top == stack_size)
62 return JS_E_STACK_OVERFLOW;
64 ctx->stack[ctx->stack_top++] = v;
65 return S_OK;
68 static inline HRESULT stack_push_string(script_ctx_t *ctx, const WCHAR *str)
70 jsstr_t *v;
72 v = jsstr_alloc(str);
73 if(!v)
74 return E_OUTOFMEMORY;
76 return stack_push(ctx, jsval_string(v));
79 static inline jsval_t stack_top(script_ctx_t *ctx)
81 assert(ctx->stack_top > ctx->call_ctx->stack_base);
82 return ctx->stack[ctx->stack_top-1];
85 static inline jsval_t *stack_top_ref(script_ctx_t *ctx, unsigned n)
87 assert(ctx->stack_top > ctx->call_ctx->stack_base+n);
88 return ctx->stack+ctx->stack_top-1-n;
91 static inline jsval_t stack_topn(script_ctx_t *ctx, unsigned n)
93 return *stack_top_ref(ctx, n);
96 static inline jsval_t *stack_args(script_ctx_t *ctx, unsigned n)
98 if(!n)
99 return NULL;
100 assert(ctx->stack_top > ctx->call_ctx->stack_base+n-1);
101 return ctx->stack + ctx->stack_top-n;
104 static inline jsval_t stack_pop(script_ctx_t *ctx)
106 assert(ctx->stack_top > ctx->call_ctx->stack_base);
107 return ctx->stack[--ctx->stack_top];
110 static void stack_popn(script_ctx_t *ctx, unsigned n)
112 while(n--)
113 jsval_release(stack_pop(ctx));
116 static HRESULT stack_pop_number(script_ctx_t *ctx, double *r)
118 jsval_t v;
119 HRESULT hres;
121 v = stack_pop(ctx);
122 hres = to_number(ctx, v, r);
123 jsval_release(v);
124 return hres;
127 static HRESULT stack_pop_object(script_ctx_t *ctx, IDispatch **r)
129 jsval_t v;
130 HRESULT hres;
132 v = stack_pop(ctx);
133 if(is_object_instance(v)) {
134 if(!get_object(v))
135 return JS_E_OBJECT_REQUIRED;
136 *r = get_object(v);
137 return S_OK;
140 hres = to_object(ctx, v, r);
141 jsval_release(v);
142 return hres;
145 static inline HRESULT stack_pop_int(script_ctx_t *ctx, INT *r)
147 return to_int32(ctx, stack_pop(ctx), r);
150 static inline HRESULT stack_pop_uint(script_ctx_t *ctx, DWORD *r)
152 return to_uint32(ctx, stack_pop(ctx), r);
155 static inline unsigned local_off(call_frame_t *frame, int ref)
157 return ref < 0
158 ? frame->arguments_off - ref-1
159 : frame->variables_off + ref;
162 static inline BSTR local_name(call_frame_t *frame, int ref)
164 return ref < 0 ? frame->function->params[-ref-1] : frame->function->variables[ref].name;
167 /* Steals input reference even on failure. */
168 static HRESULT stack_push_exprval(script_ctx_t *ctx, exprval_t *val)
170 HRESULT hres;
172 switch(val->type) {
173 case EXPRVAL_JSVAL:
174 hres = stack_push(ctx, jsval_null());
175 if(SUCCEEDED(hres))
176 hres = stack_push(ctx, val->u.val);
177 return hres;
178 case EXPRVAL_IDREF:
179 hres = stack_push(ctx, jsval_disp(val->u.idref.disp));
180 if(SUCCEEDED(hres))
181 hres = stack_push(ctx, jsval_number(val->u.idref.id));
182 else
183 IDispatch_Release(val->u.idref.disp);
184 return hres;
185 case EXPRVAL_STACK_REF:
186 hres = stack_push(ctx, jsval_number(val->u.off));
187 if(SUCCEEDED(hres))
188 hres = stack_push(ctx, jsval_undefined());
189 return hres;
190 case EXPRVAL_INVALID:
191 hres = stack_push(ctx, jsval_undefined());
192 if(SUCCEEDED(hres))
193 hres = stack_push(ctx, jsval_number(val->u.hres));
194 return hres;
197 assert(0);
198 return E_FAIL;
201 static BOOL stack_topn_exprval(script_ctx_t *ctx, unsigned n, exprval_t *r)
203 jsval_t v = stack_topn(ctx, n+1);
205 switch(jsval_type(v)) {
206 case JSV_NUMBER: {
207 call_frame_t *frame = ctx->call_ctx;
208 unsigned off = get_number(v);
210 if(!frame->base_scope->frame && off >= frame->arguments_off) {
211 DISPID id;
212 BSTR name;
213 HRESULT hres;
215 /* Got stack reference in deoptimized code. Need to convert it back to variable object reference. */
217 assert(off < frame->variables_off + frame->function->var_cnt);
218 name = off >= frame->variables_off
219 ? frame->function->variables[off - frame->variables_off].name
220 : frame->function->params[off - frame->arguments_off];
221 hres = jsdisp_get_id(ctx->call_ctx->base_scope->jsobj, name, 0, &id);
222 if(FAILED(hres)) {
223 r->type = EXPRVAL_INVALID;
224 r->u.hres = hres;
225 return FALSE;
228 *stack_top_ref(ctx, n+1) = jsval_obj(jsdisp_addref(frame->base_scope->jsobj));
229 *stack_top_ref(ctx, n) = jsval_number(id);
230 r->type = EXPRVAL_IDREF;
231 r->u.idref.disp = frame->base_scope->obj;
232 r->u.idref.id = id;
233 return TRUE;
236 r->type = EXPRVAL_STACK_REF;
237 r->u.off = off;
238 return TRUE;
240 case JSV_OBJECT:
241 r->type = EXPRVAL_IDREF;
242 r->u.idref.disp = get_object(v);
243 assert(is_number(stack_topn(ctx, n)));
244 r->u.idref.id = get_number(stack_topn(ctx, n));
245 return TRUE;
246 case JSV_UNDEFINED:
247 r->type = EXPRVAL_INVALID;
248 assert(is_number(stack_topn(ctx, n)));
249 r->u.hres = get_number(stack_topn(ctx, n));
250 return FALSE;
251 case JSV_NULL:
252 r->type = EXPRVAL_JSVAL;
253 r->u.val = stack_topn(ctx, n);
254 return TRUE;
255 default:
256 assert(0);
257 return FALSE;
261 static inline BOOL stack_pop_exprval(script_ctx_t *ctx, exprval_t *r)
263 BOOL ret = stack_topn_exprval(ctx, 0, r);
264 ctx->stack_top -= 2;
265 return ret;
268 static HRESULT exprval_propput(script_ctx_t *ctx, exprval_t *ref, jsval_t v)
270 switch(ref->type) {
271 case EXPRVAL_STACK_REF: {
272 jsval_t *r = ctx->stack + ref->u.off;
273 jsval_release(*r);
274 return jsval_copy(v, r);
276 case EXPRVAL_IDREF:
277 return disp_propput(ctx, ref->u.idref.disp, ref->u.idref.id, v);
278 case EXPRVAL_JSVAL:
279 WARN("ignoring an attempt to set value reference\n");
280 return S_OK;
281 default:
282 assert(0);
283 return E_FAIL;
287 static HRESULT exprval_propget(script_ctx_t *ctx, exprval_t *ref, jsval_t *r)
289 switch(ref->type) {
290 case EXPRVAL_STACK_REF:
291 return jsval_copy(ctx->stack[ref->u.off], r);
292 case EXPRVAL_IDREF:
293 return disp_propget(ctx, ref->u.idref.disp, ref->u.idref.id, r);
294 case EXPRVAL_JSVAL:
295 return jsval_copy(ref->u.val, r);
296 default:
297 assert(0);
298 return E_FAIL;
302 static HRESULT exprval_call(script_ctx_t *ctx, exprval_t *ref, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
304 switch(ref->type) {
305 case EXPRVAL_STACK_REF: {
306 jsval_t v = ctx->stack[ref->u.off];
308 if(!is_object_instance(v)) {
309 FIXME("invoke %s\n", debugstr_jsval(v));
310 return E_FAIL;
313 return disp_call_value(ctx, get_object(v), NULL, flags, argc, argv, r);
315 case EXPRVAL_IDREF:
316 return disp_call(ctx, ref->u.idref.disp, ref->u.idref.id, flags, argc, argv, r);
317 case EXPRVAL_JSVAL: {
318 IDispatch *obj;
319 HRESULT hres;
321 hres = to_object(ctx, ref->u.val, &obj);
322 if(SUCCEEDED(hres)) {
323 hres = disp_call_value(ctx, obj, NULL, flags, argc, argv, r);
324 IDispatch_Release(obj);
326 return hres;
328 default:
329 assert(0);
330 return E_FAIL;
334 /* ECMA-262 3rd Edition 8.7.1 */
335 /* Steals input reference. */
336 static HRESULT exprval_to_value(script_ctx_t *ctx, exprval_t *ref, jsval_t *r)
338 HRESULT hres;
340 if(ref->type == EXPRVAL_JSVAL) {
341 *r = ref->u.val;
342 return S_OK;
345 hres = exprval_propget(ctx, ref, r);
347 if(ref->type == EXPRVAL_IDREF)
348 IDispatch_Release(ref->u.idref.disp);
349 return hres;
352 static void exprval_release(exprval_t *val)
354 switch(val->type) {
355 case EXPRVAL_JSVAL:
356 jsval_release(val->u.val);
357 return;
358 case EXPRVAL_IDREF:
359 if(val->u.idref.disp)
360 IDispatch_Release(val->u.idref.disp);
361 return;
362 case EXPRVAL_STACK_REF:
363 case EXPRVAL_INVALID:
364 return;
368 static inline void exprval_set_exception(exprval_t *val, HRESULT hres)
370 val->type = EXPRVAL_INVALID;
371 val->u.hres = hres;
374 static inline void exprval_set_disp_ref(exprval_t *ref, IDispatch *obj, DISPID id)
376 ref->type = EXPRVAL_IDREF;
377 IDispatch_AddRef(ref->u.idref.disp = obj);
378 ref->u.idref.id = id;
381 static inline jsval_t steal_ret(call_frame_t *frame)
383 jsval_t r = frame->ret;
384 frame->ret = jsval_undefined();
385 return r;
388 static inline void clear_acc(script_ctx_t *ctx)
390 jsval_release(ctx->acc);
391 ctx->acc = jsval_undefined();
394 static HRESULT scope_push(scope_chain_t *scope, jsdisp_t *jsobj, IDispatch *obj, scope_chain_t **ret)
396 scope_chain_t *new_scope;
398 new_scope = heap_alloc(sizeof(scope_chain_t));
399 if(!new_scope)
400 return E_OUTOFMEMORY;
402 new_scope->ref = 1;
404 IDispatch_AddRef(obj);
405 new_scope->jsobj = jsobj;
406 new_scope->obj = obj;
407 new_scope->frame = NULL;
408 new_scope->next = scope ? scope_addref(scope) : NULL;
410 *ret = new_scope;
411 return S_OK;
414 static void scope_pop(scope_chain_t **scope)
416 scope_chain_t *tmp;
418 tmp = *scope;
419 *scope = tmp->next;
420 scope_release(tmp);
423 void scope_release(scope_chain_t *scope)
425 if(--scope->ref)
426 return;
428 if(scope->next)
429 scope_release(scope->next);
431 IDispatch_Release(scope->obj);
432 heap_free(scope);
435 static HRESULT disp_get_id(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name, BSTR name_bstr, DWORD flags, DISPID *id)
437 IDispatchEx *dispex;
438 jsdisp_t *jsdisp;
439 BSTR bstr;
440 HRESULT hres;
442 jsdisp = iface_to_jsdisp(disp);
443 if(jsdisp) {
444 hres = jsdisp_get_id(jsdisp, name, flags, id);
445 jsdisp_release(jsdisp);
446 return hres;
449 if(name_bstr) {
450 bstr = name_bstr;
451 }else {
452 bstr = SysAllocString(name);
453 if(!bstr)
454 return E_OUTOFMEMORY;
457 *id = 0;
458 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
459 if(SUCCEEDED(hres)) {
460 hres = IDispatchEx_GetDispID(dispex, bstr, make_grfdex(ctx, flags|fdexNameCaseSensitive), id);
461 IDispatchEx_Release(dispex);
462 }else {
463 TRACE("using IDispatch\n");
464 hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, id);
467 if(name_bstr != bstr)
468 SysFreeString(bstr);
469 return hres;
472 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, BOOL *ret)
474 IObjectIdentity *identity;
475 IUnknown *unk1, *unk2;
476 HRESULT hres;
478 if(disp1 == disp2) {
479 *ret = TRUE;
480 return S_OK;
483 if(!disp1 || !disp2) {
484 *ret = FALSE;
485 return S_OK;
488 hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
489 if(FAILED(hres))
490 return hres;
492 hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
493 if(FAILED(hres)) {
494 IUnknown_Release(unk1);
495 return hres;
498 if(unk1 == unk2) {
499 *ret = TRUE;
500 }else {
501 hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
502 if(SUCCEEDED(hres)) {
503 hres = IObjectIdentity_IsEqualObject(identity, unk2);
504 IObjectIdentity_Release(identity);
505 *ret = hres == S_OK;
506 }else {
507 *ret = FALSE;
511 IUnknown_Release(unk1);
512 IUnknown_Release(unk2);
513 return S_OK;
516 /* ECMA-262 3rd Edition 11.9.6 */
517 HRESULT jsval_strict_equal(jsval_t lval, jsval_t rval, BOOL *ret)
519 jsval_type_t type = jsval_type(lval);
521 TRACE("\n");
523 if(type != jsval_type(rval)) {
524 if(is_null_instance(lval))
525 *ret = is_null_instance(rval);
526 else
527 *ret = FALSE;
528 return S_OK;
531 switch(type) {
532 case JSV_UNDEFINED:
533 case JSV_NULL:
534 *ret = TRUE;
535 break;
536 case JSV_OBJECT:
537 return disp_cmp(get_object(lval), get_object(rval), ret);
538 case JSV_STRING:
539 *ret = jsstr_eq(get_string(lval), get_string(rval));
540 break;
541 case JSV_NUMBER:
542 *ret = get_number(lval) == get_number(rval);
543 break;
544 case JSV_BOOL:
545 *ret = !get_bool(lval) == !get_bool(rval);
546 break;
547 case JSV_VARIANT:
548 WARN("VARIANT type, returning false\n");
549 *ret = FALSE;
550 return S_OK;
553 return S_OK;
557 * Transfers local variables from stack to variable object.
558 * It's slow, so we want to avoid it as much as possible.
560 static HRESULT detach_variable_object(script_ctx_t *ctx, call_frame_t *frame, BOOL from_release)
562 unsigned i;
563 HRESULT hres;
565 if(!frame->base_scope || !frame->base_scope->frame)
566 return S_OK;
568 TRACE("detaching %p\n", frame);
570 assert(frame == frame->base_scope->frame);
571 assert(frame->variable_obj == frame->base_scope->jsobj);
573 if(!from_release && !frame->arguments_obj) {
574 hres = setup_arguments_object(ctx, frame);
575 if(FAILED(hres))
576 return hres;
579 frame->base_scope->frame = NULL;
581 for(i = 0; i < frame->function->locals_cnt; i++) {
582 hres = jsdisp_propput_name(frame->variable_obj, frame->function->locals[i].name,
583 ctx->stack[local_off(frame, frame->function->locals[i].ref)]);
584 if(FAILED(hres))
585 return hres;
588 return S_OK;
591 static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
593 named_item_t *item;
594 DISPID id;
595 HRESULT hres;
597 LIST_FOR_EACH_ENTRY(item, &ctx->named_items, named_item_t, entry) {
598 if(item->flags & SCRIPTITEM_GLOBALMEMBERS) {
599 hres = disp_get_id(ctx, item->disp, identifier, identifier, 0, &id);
600 if(SUCCEEDED(hres)) {
601 if(ret)
602 exprval_set_disp_ref(ret, item->disp, id);
603 return TRUE;
608 return FALSE;
611 IDispatch *lookup_global_host(script_ctx_t *ctx)
613 IDispatch *disp = NULL;
614 named_item_t *item;
616 LIST_FOR_EACH_ENTRY(item, &ctx->named_items, named_item_t, entry) {
617 if(!(item->flags & SCRIPTITEM_GLOBALMEMBERS)) continue;
618 disp = item->disp;
619 break;
621 if(!disp) disp = to_disp(ctx->global);
623 return disp;
626 static int __cdecl local_ref_cmp(const void *key, const void *ref)
628 return wcscmp((const WCHAR*)key, ((const local_ref_t*)ref)->name);
631 local_ref_t *lookup_local(const function_code_t *function, const WCHAR *identifier)
633 return bsearch(identifier, function->locals, function->locals_cnt, sizeof(*function->locals), local_ref_cmp);
636 /* ECMA-262 3rd Edition 10.1.4 */
637 static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
639 scope_chain_t *scope;
640 named_item_t *item;
641 DISPID id = 0;
642 HRESULT hres;
644 TRACE("%s\n", debugstr_w(identifier));
646 if(ctx->call_ctx) {
647 for(scope = ctx->call_ctx->scope; scope; scope = scope->next) {
648 if(scope->frame) {
649 function_code_t *func = scope->frame->function;
650 local_ref_t *ref = lookup_local(func, identifier);
652 if(ref) {
653 ret->type = EXPRVAL_STACK_REF;
654 ret->u.off = local_off(scope->frame, ref->ref);
655 TRACE("returning ref %d for %d\n", ret->u.off, ref->ref);
656 return S_OK;
659 if(!wcscmp(identifier, L"arguments")) {
660 hres = detach_variable_object(ctx, scope->frame, FALSE);
661 if(FAILED(hres))
662 return hres;
665 /* ECMA-262 5.1 Edition 13 */
666 if(func->name && ctx->version >= SCRIPTLANGUAGEVERSION_ES5 && !wcscmp(identifier, func->name)) {
667 TRACE("returning a function from scope chain\n");
668 ret->type = EXPRVAL_JSVAL;
669 ret->u.val = jsval_obj(jsdisp_addref(scope->frame->function_instance));
670 return S_OK;
673 if(scope->jsobj)
674 hres = jsdisp_get_id(scope->jsobj, identifier, fdexNameImplicit, &id);
675 else
676 hres = disp_get_id(ctx, scope->obj, identifier, identifier, fdexNameImplicit, &id);
677 if(SUCCEEDED(hres)) {
678 exprval_set_disp_ref(ret, scope->obj, id);
679 return S_OK;
683 item = ctx->call_ctx->bytecode->named_item;
684 if(item) {
685 hres = jsdisp_get_id(item->script_obj, identifier, 0, &id);
686 if(SUCCEEDED(hres)) {
687 exprval_set_disp_ref(ret, to_disp(item->script_obj), id);
688 return S_OK;
690 if(!(item->flags & SCRIPTITEM_CODEONLY)) {
691 hres = disp_get_id(ctx, item->disp, identifier, identifier, 0, &id);
692 if(SUCCEEDED(hres)) {
693 exprval_set_disp_ref(ret, item->disp, id);
694 return S_OK;
700 hres = jsdisp_get_id(ctx->global, identifier, 0, &id);
701 if(SUCCEEDED(hres)) {
702 exprval_set_disp_ref(ret, to_disp(ctx->global), id);
703 return S_OK;
706 item = lookup_named_item(ctx, identifier, SCRIPTITEM_ISVISIBLE);
707 if(item) {
708 IDispatch_AddRef(item->disp);
709 ret->type = EXPRVAL_JSVAL;
710 ret->u.val = jsval_disp(item->disp);
711 return S_OK;
714 if(lookup_global_members(ctx, identifier, ret))
715 return S_OK;
717 exprval_set_exception(ret, JS_E_UNDEFINED_VARIABLE);
718 return S_OK;
721 static inline BSTR get_op_bstr(script_ctx_t *ctx, int i)
723 call_frame_t *frame = ctx->call_ctx;
724 return frame->bytecode->instrs[frame->ip].u.arg[i].bstr;
727 static inline unsigned get_op_uint(script_ctx_t *ctx, int i)
729 call_frame_t *frame = ctx->call_ctx;
730 return frame->bytecode->instrs[frame->ip].u.arg[i].uint;
733 static inline unsigned get_op_int(script_ctx_t *ctx, int i)
735 call_frame_t *frame = ctx->call_ctx;
736 return frame->bytecode->instrs[frame->ip].u.arg[i].lng;
739 static inline jsstr_t *get_op_str(script_ctx_t *ctx, int i)
741 call_frame_t *frame = ctx->call_ctx;
742 return frame->bytecode->instrs[frame->ip].u.arg[i].str;
745 static inline double get_op_double(script_ctx_t *ctx)
747 call_frame_t *frame = ctx->call_ctx;
748 return frame->bytecode->instrs[frame->ip].u.dbl;
751 static inline void jmp_next(script_ctx_t *ctx)
753 ctx->call_ctx->ip++;
756 static inline void jmp_abs(script_ctx_t *ctx, unsigned dst)
758 ctx->call_ctx->ip = dst;
761 /* ECMA-262 3rd Edition 12.6.4 */
762 static HRESULT interp_forin(script_ctx_t *ctx)
764 const HRESULT arg = get_op_uint(ctx, 0);
765 IDispatch *obj = NULL;
766 IDispatchEx *dispex;
767 exprval_t prop_ref;
768 DISPID id;
769 BSTR name = NULL;
770 HRESULT hres;
772 TRACE("\n");
774 assert(is_number(stack_top(ctx)));
775 id = get_number(stack_top(ctx));
777 if(!stack_topn_exprval(ctx, 1, &prop_ref)) {
778 FIXME("invalid ref: %08x\n", prop_ref.u.hres);
779 return E_FAIL;
782 if(is_object_instance(stack_topn(ctx, 3)))
783 obj = get_object(stack_topn(ctx, 3));
785 if(obj) {
786 hres = IDispatch_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
787 if(SUCCEEDED(hres)) {
788 hres = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, id, &id);
789 if(hres == S_OK)
790 hres = IDispatchEx_GetMemberName(dispex, id, &name);
791 IDispatchEx_Release(dispex);
792 if(FAILED(hres))
793 return hres;
794 }else {
795 TRACE("No IDispatchEx\n");
799 if(name) {
800 jsstr_t *str;
802 str = jsstr_alloc_len(name, SysStringLen(name));
803 SysFreeString(name);
804 if(!str)
805 return E_OUTOFMEMORY;
807 stack_pop(ctx);
808 stack_push(ctx, jsval_number(id)); /* safe, just after pop() */
810 hres = exprval_propput(ctx, &prop_ref, jsval_string(str));
811 jsstr_release(str);
812 if(FAILED(hres))
813 return hres;
815 jmp_next(ctx);
816 }else {
817 stack_popn(ctx, 4);
818 jmp_abs(ctx, arg);
820 return S_OK;
823 /* ECMA-262 3rd Edition 12.10 */
824 static HRESULT interp_push_scope(script_ctx_t *ctx)
826 IDispatch *disp;
827 jsval_t v;
828 HRESULT hres;
830 TRACE("\n");
832 v = stack_pop(ctx);
833 hres = to_object(ctx, v, &disp);
834 jsval_release(v);
835 if(FAILED(hres))
836 return hres;
838 hres = scope_push(ctx->call_ctx->scope, to_jsdisp(disp), disp, &ctx->call_ctx->scope);
839 IDispatch_Release(disp);
840 return hres;
843 /* ECMA-262 3rd Edition 12.10 */
844 static HRESULT interp_pop_scope(script_ctx_t *ctx)
846 TRACE("\n");
848 scope_pop(&ctx->call_ctx->scope);
849 return S_OK;
852 /* ECMA-262 3rd Edition 12.13 */
853 static HRESULT interp_case(script_ctx_t *ctx)
855 const unsigned arg = get_op_uint(ctx, 0);
856 jsval_t v;
857 BOOL b;
858 HRESULT hres;
860 TRACE("\n");
862 v = stack_pop(ctx);
863 hres = jsval_strict_equal(stack_top(ctx), v, &b);
864 jsval_release(v);
865 if(FAILED(hres))
866 return hres;
868 if(b) {
869 stack_popn(ctx, 1);
870 jmp_abs(ctx, arg);
871 }else {
872 jmp_next(ctx);
874 return S_OK;
877 static void set_error_value(script_ctx_t *ctx, jsval_t value)
879 jsexcept_t *ei = ctx->ei;
880 jsdisp_t *obj;
882 reset_ei(ei);
883 ei->error = JS_E_EXCEPTION_THROWN;
884 ei->valid_value = TRUE;
885 ei->value = value;
887 if(is_object_instance(value) && get_object(value) && (obj = to_jsdisp(get_object(value)))) {
888 UINT32 number;
889 jsstr_t *str;
890 jsval_t v;
891 HRESULT hres;
893 /* FIXME: We should check if object is an error instance */
895 hres = jsdisp_propget_name(obj, L"number", &v);
896 if(SUCCEEDED(hres)) {
897 hres = to_uint32(ctx, v, &number);
898 if(SUCCEEDED(hres))
899 ei->error = FAILED(number) ? number : E_FAIL;
900 jsval_release(v);
903 hres = jsdisp_propget_name(obj, L"description", &v);
904 if(SUCCEEDED(hres)) {
905 hres = to_string(ctx, v, &str);
906 if(SUCCEEDED(hres))
907 ei->message = str;
908 jsval_release(v);
913 /* ECMA-262 3rd Edition 12.13 */
914 static HRESULT interp_throw(script_ctx_t *ctx)
916 TRACE("\n");
918 set_error_value(ctx, stack_pop(ctx));
919 return DISP_E_EXCEPTION;
922 static HRESULT interp_throw_ref(script_ctx_t *ctx)
924 const HRESULT arg = get_op_uint(ctx, 0);
926 TRACE("%08x\n", arg);
928 return arg;
931 static HRESULT interp_throw_type(script_ctx_t *ctx)
933 const HRESULT hres = get_op_uint(ctx, 0);
934 jsstr_t *str = get_op_str(ctx, 1);
935 const WCHAR *ptr;
937 TRACE("%08x %s\n", hres, debugstr_jsstr(str));
939 ptr = jsstr_flatten(str);
940 return ptr ? throw_error(ctx, hres, ptr) : E_OUTOFMEMORY;
943 /* ECMA-262 3rd Edition 12.14 */
944 static HRESULT interp_push_except(script_ctx_t *ctx)
946 const unsigned catch_off = get_op_uint(ctx, 0);
947 const unsigned finally_off = get_op_uint(ctx, 1);
948 call_frame_t *frame = ctx->call_ctx;
949 except_frame_t *except;
951 TRACE("\n");
953 except = heap_alloc(sizeof(*except));
954 if(!except)
955 return E_OUTOFMEMORY;
957 except->stack_top = ctx->stack_top;
958 except->scope = frame->scope;
959 except->catch_off = catch_off;
960 except->finally_off = finally_off;
961 except->next = frame->except_frame;
962 frame->except_frame = except;
963 return S_OK;
966 /* ECMA-262 3rd Edition 12.14 */
967 static HRESULT interp_pop_except(script_ctx_t *ctx)
969 const unsigned ret_off = get_op_uint(ctx, 0);
970 call_frame_t *frame = ctx->call_ctx;
971 except_frame_t *except;
972 unsigned finally_off;
974 TRACE("%u\n", ret_off);
976 except = frame->except_frame;
977 assert(except != NULL);
979 finally_off = except->finally_off;
980 frame->except_frame = except->next;
981 heap_free(except);
983 if(finally_off) {
984 HRESULT hres;
986 hres = stack_push(ctx, jsval_number(ret_off));
987 if(FAILED(hres))
988 return hres;
989 hres = stack_push(ctx, jsval_bool(TRUE));
990 if(FAILED(hres))
991 return hres;
992 frame->ip = finally_off;
993 }else {
994 frame->ip = ret_off;
997 return S_OK;
1000 /* ECMA-262 3rd Edition 12.14 */
1001 static HRESULT interp_end_finally(script_ctx_t *ctx)
1003 call_frame_t *frame = ctx->call_ctx;
1004 jsval_t v;
1006 TRACE("\n");
1008 v = stack_pop(ctx);
1009 assert(is_bool(v));
1011 if(!get_bool(v)) {
1012 TRACE("passing exception\n");
1014 set_error_value(ctx, stack_pop(ctx));
1015 return DISP_E_EXCEPTION;
1018 v = stack_pop(ctx);
1019 assert(is_number(v));
1020 frame->ip = get_number(v);
1021 return S_OK;
1024 static HRESULT interp_enter_catch(script_ctx_t *ctx)
1026 const BSTR ident = get_op_bstr(ctx, 0);
1027 jsdisp_t *scope_obj;
1028 jsval_t v;
1029 HRESULT hres;
1031 hres = create_dispex(ctx, NULL, NULL, &scope_obj);
1032 if(FAILED(hres))
1033 return hres;
1035 v = stack_pop(ctx);
1036 hres = jsdisp_propput_name(scope_obj, ident, v);
1037 jsval_release(v);
1038 if(SUCCEEDED(hres))
1039 hres = scope_push(ctx->call_ctx->scope, scope_obj, to_disp(scope_obj), &ctx->call_ctx->scope);
1040 jsdisp_release(scope_obj);
1041 return hres;
1044 /* ECMA-262 3rd Edition 13 */
1045 static HRESULT interp_func(script_ctx_t *ctx)
1047 unsigned func_idx = get_op_uint(ctx, 0);
1048 call_frame_t *frame = ctx->call_ctx;
1049 jsdisp_t *dispex;
1050 HRESULT hres;
1052 TRACE("%d\n", func_idx);
1054 hres = create_source_function(ctx, frame->bytecode, frame->function->funcs+func_idx,
1055 frame->scope, &dispex);
1056 if(FAILED(hres))
1057 return hres;
1059 return stack_push(ctx, jsval_obj(dispex));
1062 /* ECMA-262 3rd Edition 11.2.1 */
1063 static HRESULT interp_array(script_ctx_t *ctx)
1065 jsstr_t *name_str;
1066 const WCHAR *name;
1067 jsval_t v, namev;
1068 IDispatch *obj;
1069 DISPID id;
1070 HRESULT hres;
1072 TRACE("\n");
1074 namev = stack_pop(ctx);
1076 hres = stack_pop_object(ctx, &obj);
1077 if(FAILED(hres)) {
1078 jsval_release(namev);
1079 return hres;
1082 hres = to_flat_string(ctx, namev, &name_str, &name);
1083 jsval_release(namev);
1084 if(FAILED(hres)) {
1085 IDispatch_Release(obj);
1086 return hres;
1089 hres = disp_get_id(ctx, obj, name, NULL, 0, &id);
1090 jsstr_release(name_str);
1091 if(SUCCEEDED(hres)) {
1092 hres = disp_propget(ctx, obj, id, &v);
1093 }else if(hres == DISP_E_UNKNOWNNAME) {
1094 v = jsval_undefined();
1095 hres = S_OK;
1097 IDispatch_Release(obj);
1098 if(FAILED(hres))
1099 return hres;
1101 return stack_push(ctx, v);
1104 /* ECMA-262 3rd Edition 11.2.1 */
1105 static HRESULT interp_member(script_ctx_t *ctx)
1107 const BSTR arg = get_op_bstr(ctx, 0);
1108 IDispatch *obj;
1109 jsval_t v;
1110 DISPID id;
1111 HRESULT hres;
1113 TRACE("\n");
1115 hres = stack_pop_object(ctx, &obj);
1116 if(FAILED(hres))
1117 return hres;
1119 hres = disp_get_id(ctx, obj, arg, arg, 0, &id);
1120 if(SUCCEEDED(hres)) {
1121 hres = disp_propget(ctx, obj, id, &v);
1122 }else if(hres == DISP_E_UNKNOWNNAME) {
1123 v = jsval_undefined();
1124 hres = S_OK;
1126 IDispatch_Release(obj);
1127 if(FAILED(hres))
1128 return hres;
1130 return stack_push(ctx, v);
1133 /* ECMA-262 3rd Edition 11.2.1 */
1134 static HRESULT interp_memberid(script_ctx_t *ctx)
1136 const unsigned arg = get_op_uint(ctx, 0);
1137 jsval_t objv, namev;
1138 const WCHAR *name;
1139 jsstr_t *name_str;
1140 IDispatch *obj;
1141 exprval_t ref;
1142 DISPID id;
1143 HRESULT hres;
1145 TRACE("%x\n", arg);
1147 namev = stack_pop(ctx);
1148 objv = stack_pop(ctx);
1150 hres = to_object(ctx, objv, &obj);
1151 jsval_release(objv);
1152 if(SUCCEEDED(hres)) {
1153 hres = to_flat_string(ctx, namev, &name_str, &name);
1154 if(FAILED(hres))
1155 IDispatch_Release(obj);
1157 jsval_release(namev);
1158 if(FAILED(hres))
1159 return hres;
1161 hres = disp_get_id(ctx, obj, name, NULL, arg, &id);
1162 jsstr_release(name_str);
1163 if(SUCCEEDED(hres)) {
1164 ref.type = EXPRVAL_IDREF;
1165 ref.u.idref.disp = obj;
1166 ref.u.idref.id = id;
1167 }else {
1168 IDispatch_Release(obj);
1169 if(hres == DISP_E_UNKNOWNNAME && !(arg & fdexNameEnsure)) {
1170 exprval_set_exception(&ref, JS_E_INVALID_PROPERTY);
1171 hres = S_OK;
1172 }else {
1173 ERR("failed %08x\n", hres);
1174 return hres;
1178 return stack_push_exprval(ctx, &ref);
1181 /* ECMA-262 3rd Edition 11.2.1 */
1182 static HRESULT interp_refval(script_ctx_t *ctx)
1184 exprval_t ref;
1185 jsval_t v;
1186 HRESULT hres;
1188 TRACE("\n");
1190 if(!stack_topn_exprval(ctx, 0, &ref))
1191 return JS_E_ILLEGAL_ASSIGN;
1193 hres = exprval_propget(ctx, &ref, &v);
1194 if(FAILED(hres))
1195 return hres;
1197 return stack_push(ctx, v);
1200 /* ECMA-262 3rd Edition 11.2.2 */
1201 static HRESULT interp_new(script_ctx_t *ctx)
1203 const unsigned argc = get_op_uint(ctx, 0);
1204 jsval_t constr;
1206 TRACE("%d\n", argc);
1208 constr = stack_topn(ctx, argc);
1210 /* NOTE: Should use to_object here */
1212 if(is_null(constr))
1213 return JS_E_OBJECT_EXPECTED;
1214 else if(!is_object_instance(constr))
1215 return JS_E_INVALID_ACTION;
1216 else if(!get_object(constr))
1217 return JS_E_INVALID_PROPERTY;
1219 clear_acc(ctx);
1220 return disp_call_value(ctx, get_object(constr), NULL, DISPATCH_CONSTRUCT | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
1221 argc, stack_args(ctx, argc), &ctx->acc);
1224 /* ECMA-262 3rd Edition 11.2.3 */
1225 static HRESULT interp_call(script_ctx_t *ctx)
1227 const unsigned argn = get_op_uint(ctx, 0);
1228 const int do_ret = get_op_int(ctx, 1);
1229 jsval_t obj;
1231 TRACE("%d %d\n", argn, do_ret);
1233 obj = stack_topn(ctx, argn);
1234 if(!is_object_instance(obj))
1235 return JS_E_INVALID_PROPERTY;
1237 clear_acc(ctx);
1238 return disp_call_value(ctx, get_object(obj), NULL, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
1239 argn, stack_args(ctx, argn), do_ret ? &ctx->acc : NULL);
1242 /* ECMA-262 3rd Edition 11.2.3 */
1243 static HRESULT interp_call_member(script_ctx_t *ctx)
1245 const unsigned argn = get_op_uint(ctx, 0);
1246 const int do_ret = get_op_int(ctx, 1);
1247 exprval_t ref;
1249 TRACE("%d %d\n", argn, do_ret);
1251 if(!stack_topn_exprval(ctx, argn, &ref))
1252 return ref.u.hres;
1254 clear_acc(ctx);
1255 return exprval_call(ctx, &ref, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
1256 argn, stack_args(ctx, argn), do_ret ? &ctx->acc : NULL);
1259 /* ECMA-262 3rd Edition 11.1.1 */
1260 static HRESULT interp_this(script_ctx_t *ctx)
1262 IDispatch *this_obj = ctx->call_ctx->this_obj;
1264 TRACE("\n");
1266 if(!this_obj) {
1267 named_item_t *item = ctx->call_ctx->bytecode->named_item;
1269 if(item)
1270 this_obj = (item->flags & SCRIPTITEM_CODEONLY) ? to_disp(item->script_obj) : item->disp;
1271 else
1272 this_obj = lookup_global_host(ctx);
1275 IDispatch_AddRef(this_obj);
1276 return stack_push(ctx, jsval_disp(this_obj));
1279 static HRESULT interp_identifier_ref(script_ctx_t *ctx, BSTR identifier, unsigned flags)
1281 exprval_t exprval;
1282 HRESULT hres;
1284 hres = identifier_eval(ctx, identifier, &exprval);
1285 if(FAILED(hres))
1286 return hres;
1288 if(exprval.type == EXPRVAL_INVALID && (flags & fdexNameEnsure)) {
1289 jsdisp_t *script_obj = ctx->global;
1290 DISPID id;
1292 if(ctx->call_ctx->bytecode->named_item)
1293 script_obj = ctx->call_ctx->bytecode->named_item->script_obj;
1295 hres = jsdisp_get_id(script_obj, identifier, fdexNameEnsure, &id);
1296 if(FAILED(hres))
1297 return hres;
1299 exprval_set_disp_ref(&exprval, to_disp(script_obj), id);
1302 if(exprval.type == EXPRVAL_INVALID ||
1303 (exprval.type == EXPRVAL_JSVAL && ctx->version < SCRIPTLANGUAGEVERSION_ES5)) {
1304 WARN("invalid ref\n");
1305 exprval_release(&exprval);
1306 exprval_set_exception(&exprval, JS_E_OBJECT_EXPECTED);
1309 return stack_push_exprval(ctx, &exprval);
1312 static HRESULT identifier_value(script_ctx_t *ctx, BSTR identifier)
1314 exprval_t exprval;
1315 jsval_t v;
1316 HRESULT hres;
1318 hres = identifier_eval(ctx, identifier, &exprval);
1319 if(FAILED(hres))
1320 return hres;
1322 if(exprval.type == EXPRVAL_INVALID)
1323 return throw_error(ctx, exprval.u.hres, identifier);
1325 hres = exprval_to_value(ctx, &exprval, &v);
1326 if(FAILED(hres))
1327 return hres;
1329 return stack_push(ctx, v);
1332 static HRESULT interp_local_ref(script_ctx_t *ctx)
1334 const int arg = get_op_int(ctx, 0);
1335 const unsigned flags = get_op_uint(ctx, 1);
1336 call_frame_t *frame = ctx->call_ctx;
1337 exprval_t ref;
1339 TRACE("%s\n", debugstr_w(local_name(frame, arg)));
1341 if(!frame->base_scope || !frame->base_scope->frame)
1342 return interp_identifier_ref(ctx, local_name(frame, arg), flags);
1344 ref.type = EXPRVAL_STACK_REF;
1345 ref.u.off = local_off(frame, arg);
1346 return stack_push_exprval(ctx, &ref);
1349 static HRESULT interp_local(script_ctx_t *ctx)
1351 const int arg = get_op_int(ctx, 0);
1352 call_frame_t *frame = ctx->call_ctx;
1353 jsval_t copy;
1354 HRESULT hres;
1356 if(!frame->base_scope || !frame->base_scope->frame) {
1357 TRACE("%s\n", debugstr_w(local_name(frame, arg)));
1358 return identifier_value(ctx, local_name(frame, arg));
1361 hres = jsval_copy(ctx->stack[local_off(frame, arg)], &copy);
1362 if(FAILED(hres))
1363 return hres;
1365 TRACE("%s: %s\n", debugstr_w(local_name(frame, arg)), debugstr_jsval(copy));
1366 return stack_push(ctx, copy);
1369 /* ECMA-262 3rd Edition 10.1.4 */
1370 static HRESULT interp_ident(script_ctx_t *ctx)
1372 const BSTR arg = get_op_bstr(ctx, 0);
1374 TRACE("%s\n", debugstr_w(arg));
1376 return identifier_value(ctx, arg);
1379 /* ECMA-262 3rd Edition 10.1.4 */
1380 static HRESULT interp_identid(script_ctx_t *ctx)
1382 const BSTR arg = get_op_bstr(ctx, 0);
1383 const unsigned flags = get_op_uint(ctx, 1);
1385 TRACE("%s %x\n", debugstr_w(arg), flags);
1387 return interp_identifier_ref(ctx, arg, flags);
1390 /* ECMA-262 3rd Edition 7.8.1 */
1391 static HRESULT interp_null(script_ctx_t *ctx)
1393 TRACE("\n");
1395 return stack_push(ctx, jsval_null());
1398 /* ECMA-262 3rd Edition 7.8.2 */
1399 static HRESULT interp_bool(script_ctx_t *ctx)
1401 const int arg = get_op_int(ctx, 0);
1403 TRACE("%s\n", arg ? "true" : "false");
1405 return stack_push(ctx, jsval_bool(arg));
1408 /* ECMA-262 3rd Edition 7.8.3 */
1409 static HRESULT interp_int(script_ctx_t *ctx)
1411 const int arg = get_op_int(ctx, 0);
1413 TRACE("%d\n", arg);
1415 return stack_push(ctx, jsval_number(arg));
1418 /* ECMA-262 3rd Edition 7.8.3 */
1419 static HRESULT interp_double(script_ctx_t *ctx)
1421 const double arg = get_op_double(ctx);
1423 TRACE("%lf\n", arg);
1425 return stack_push(ctx, jsval_number(arg));
1428 /* ECMA-262 3rd Edition 7.8.4 */
1429 static HRESULT interp_str(script_ctx_t *ctx)
1431 jsstr_t *str = get_op_str(ctx, 0);
1433 TRACE("%s\n", debugstr_jsstr(str));
1435 return stack_push(ctx, jsval_string(jsstr_addref(str)));
1438 /* ECMA-262 3rd Edition 7.8 */
1439 static HRESULT interp_regexp(script_ctx_t *ctx)
1441 jsstr_t *source = get_op_str(ctx, 0);
1442 const unsigned flags = get_op_uint(ctx, 1);
1443 jsdisp_t *regexp;
1444 HRESULT hres;
1446 TRACE("%s %x\n", debugstr_jsstr(source), flags);
1448 hres = create_regexp(ctx, source, flags, &regexp);
1449 if(FAILED(hres))
1450 return hres;
1452 return stack_push(ctx, jsval_obj(regexp));
1455 /* ECMA-262 3rd Edition 11.1.4 */
1456 static HRESULT interp_carray(script_ctx_t *ctx)
1458 const unsigned arg = get_op_uint(ctx, 0);
1459 jsdisp_t *array;
1460 HRESULT hres;
1462 TRACE("%u\n", arg);
1464 hres = create_array(ctx, arg, &array);
1465 if(FAILED(hres))
1466 return hres;
1468 return stack_push(ctx, jsval_obj(array));
1471 static HRESULT interp_carray_set(script_ctx_t *ctx)
1473 const unsigned index = get_op_uint(ctx, 0);
1474 jsval_t value, array;
1475 HRESULT hres;
1477 value = stack_pop(ctx);
1479 TRACE("[%u] = %s\n", index, debugstr_jsval(value));
1481 array = stack_top(ctx);
1482 assert(is_object_instance(array));
1484 hres = jsdisp_propput_idx(iface_to_jsdisp(get_object(array)), index, value);
1485 jsval_release(value);
1486 return hres;
1489 /* ECMA-262 3rd Edition 11.1.5 */
1490 static HRESULT interp_new_obj(script_ctx_t *ctx)
1492 jsdisp_t *obj;
1493 HRESULT hres;
1495 TRACE("\n");
1497 hres = create_object(ctx, NULL, &obj);
1498 if(FAILED(hres))
1499 return hres;
1501 return stack_push(ctx, jsval_obj(obj));
1504 /* ECMA-262 3rd Edition 11.1.5 */
1505 static HRESULT interp_obj_prop(script_ctx_t *ctx)
1507 jsstr_t *name_arg = get_op_str(ctx, 0);
1508 unsigned type = get_op_uint(ctx, 1);
1509 const WCHAR *name;
1510 jsdisp_t *obj;
1511 jsval_t val;
1512 HRESULT hres;
1514 TRACE("%s\n", debugstr_jsstr(name_arg));
1516 val = stack_pop(ctx);
1518 /* FIXME: we should pass it as jsstr_t */
1519 name = jsstr_flatten(name_arg);
1521 assert(is_object_instance(stack_top(ctx)));
1522 obj = as_jsdisp(get_object(stack_top(ctx)));
1524 if(type == PROPERTY_DEFINITION_VALUE) {
1525 hres = jsdisp_propput_name(obj, name, val);
1526 }else {
1527 property_desc_t desc = {PROPF_ENUMERABLE | PROPF_CONFIGURABLE};
1528 jsdisp_t *func;
1530 assert(is_object_instance(val));
1531 func = iface_to_jsdisp(get_object(val));
1533 desc.mask = desc.flags;
1534 if(type == PROPERTY_DEFINITION_GETTER) {
1535 desc.explicit_getter = TRUE;
1536 desc.getter = func;
1537 }else {
1538 desc.explicit_setter = TRUE;
1539 desc.setter = func;
1542 hres = jsdisp_define_property(obj, name, &desc);
1543 jsdisp_release(func);
1546 jsval_release(val);
1547 return hres;
1550 /* ECMA-262 3rd Edition 11.11 */
1551 static HRESULT interp_cnd_nz(script_ctx_t *ctx)
1553 const unsigned arg = get_op_uint(ctx, 0);
1554 BOOL b;
1555 HRESULT hres;
1557 TRACE("\n");
1559 hres = to_boolean(stack_top(ctx), &b);
1560 if(FAILED(hres))
1561 return hres;
1563 if(b) {
1564 jmp_abs(ctx, arg);
1565 }else {
1566 stack_popn(ctx, 1);
1567 jmp_next(ctx);
1569 return S_OK;
1572 /* ECMA-262 3rd Edition 11.11 */
1573 static HRESULT interp_cnd_z(script_ctx_t *ctx)
1575 const unsigned arg = get_op_uint(ctx, 0);
1576 BOOL b;
1577 HRESULT hres;
1579 TRACE("\n");
1581 hres = to_boolean(stack_top(ctx), &b);
1582 if(FAILED(hres))
1583 return hres;
1585 if(b) {
1586 stack_popn(ctx, 1);
1587 jmp_next(ctx);
1588 }else {
1589 jmp_abs(ctx, arg);
1591 return S_OK;
1594 /* ECMA-262 3rd Edition 11.10 */
1595 static HRESULT interp_or(script_ctx_t *ctx)
1597 INT l, r;
1598 HRESULT hres;
1600 TRACE("\n");
1602 hres = stack_pop_int(ctx, &r);
1603 if(FAILED(hres))
1604 return hres;
1606 hres = stack_pop_int(ctx, &l);
1607 if(FAILED(hres))
1608 return hres;
1610 return stack_push(ctx, jsval_number(l|r));
1613 /* ECMA-262 3rd Edition 11.10 */
1614 static HRESULT interp_xor(script_ctx_t *ctx)
1616 INT l, r;
1617 HRESULT hres;
1619 TRACE("\n");
1621 hres = stack_pop_int(ctx, &r);
1622 if(FAILED(hres))
1623 return hres;
1625 hres = stack_pop_int(ctx, &l);
1626 if(FAILED(hres))
1627 return hres;
1629 return stack_push(ctx, jsval_number(l^r));
1632 /* ECMA-262 3rd Edition 11.10 */
1633 static HRESULT interp_and(script_ctx_t *ctx)
1635 INT l, r;
1636 HRESULT hres;
1638 TRACE("\n");
1640 hres = stack_pop_int(ctx, &r);
1641 if(FAILED(hres))
1642 return hres;
1644 hres = stack_pop_int(ctx, &l);
1645 if(FAILED(hres))
1646 return hres;
1648 return stack_push(ctx, jsval_number(l&r));
1651 /* ECMA-262 3rd Edition 11.8.6 */
1652 static HRESULT interp_instanceof(script_ctx_t *ctx)
1654 jsdisp_t *obj, *iter, *tmp = NULL;
1655 jsval_t prot, v;
1656 BOOL ret = FALSE;
1657 HRESULT hres;
1659 v = stack_pop(ctx);
1660 if(!is_object_instance(v) || !get_object(v)) {
1661 jsval_release(v);
1662 return JS_E_FUNCTION_EXPECTED;
1665 obj = iface_to_jsdisp(get_object(v));
1666 IDispatch_Release(get_object(v));
1667 if(!obj) {
1668 FIXME("non-jsdisp objects not supported\n");
1669 return E_FAIL;
1672 if(is_class(obj, JSCLASS_FUNCTION)) {
1673 hres = jsdisp_propget_name(obj, L"prototype", &prot);
1674 }else {
1675 hres = JS_E_FUNCTION_EXPECTED;
1677 jsdisp_release(obj);
1678 if(FAILED(hres))
1679 return hres;
1681 v = stack_pop(ctx);
1683 if(is_object_instance(prot)) {
1684 if(is_object_instance(v))
1685 tmp = iface_to_jsdisp(get_object(v));
1686 for(iter = tmp; !ret && iter; iter = iter->prototype) {
1687 hres = disp_cmp(get_object(prot), to_disp(iter), &ret);
1688 if(FAILED(hres))
1689 break;
1692 if(tmp)
1693 jsdisp_release(tmp);
1694 }else {
1695 FIXME("prototype is not an object\n");
1696 hres = E_FAIL;
1699 jsval_release(prot);
1700 jsval_release(v);
1701 if(FAILED(hres))
1702 return hres;
1704 return stack_push(ctx, jsval_bool(ret));
1707 /* ECMA-262 3rd Edition 11.8.7 */
1708 static HRESULT interp_in(script_ctx_t *ctx)
1710 const WCHAR *str;
1711 jsstr_t *jsstr;
1712 jsval_t obj, v;
1713 DISPID id = 0;
1714 BOOL ret;
1715 HRESULT hres;
1717 TRACE("\n");
1719 obj = stack_pop(ctx);
1720 if(!is_object_instance(obj) || !get_object(obj)) {
1721 jsval_release(obj);
1722 return JS_E_OBJECT_EXPECTED;
1725 v = stack_pop(ctx);
1726 hres = to_flat_string(ctx, v, &jsstr, &str);
1727 jsval_release(v);
1728 if(FAILED(hres)) {
1729 IDispatch_Release(get_object(obj));
1730 return hres;
1733 hres = disp_get_id(ctx, get_object(obj), str, NULL, 0, &id);
1734 IDispatch_Release(get_object(obj));
1735 jsstr_release(jsstr);
1736 if(SUCCEEDED(hres))
1737 ret = TRUE;
1738 else if(hres == DISP_E_UNKNOWNNAME)
1739 ret = FALSE;
1740 else
1741 return hres;
1743 return stack_push(ctx, jsval_bool(ret));
1746 /* ECMA-262 3rd Edition 11.6.1 */
1747 static HRESULT interp_add(script_ctx_t *ctx)
1749 jsval_t l, r, lval, rval, ret;
1750 HRESULT hres;
1752 rval = stack_pop(ctx);
1753 lval = stack_pop(ctx);
1755 TRACE("%s + %s\n", debugstr_jsval(lval), debugstr_jsval(rval));
1757 hres = to_primitive(ctx, lval, &l, NO_HINT);
1758 if(SUCCEEDED(hres)) {
1759 hres = to_primitive(ctx, rval, &r, NO_HINT);
1760 if(FAILED(hres))
1761 jsval_release(l);
1763 jsval_release(lval);
1764 jsval_release(rval);
1765 if(FAILED(hres))
1766 return hres;
1768 if(is_string(l) || is_string(r)) {
1769 jsstr_t *lstr, *rstr = NULL;
1771 hres = to_string(ctx, l, &lstr);
1772 if(SUCCEEDED(hres))
1773 hres = to_string(ctx, r, &rstr);
1775 if(SUCCEEDED(hres)) {
1776 jsstr_t *ret_str;
1778 ret_str = jsstr_concat(lstr, rstr);
1779 if(ret_str)
1780 ret = jsval_string(ret_str);
1781 else
1782 hres = E_OUTOFMEMORY;
1785 jsstr_release(lstr);
1786 if(rstr)
1787 jsstr_release(rstr);
1788 }else {
1789 double nl, nr;
1791 hres = to_number(ctx, l, &nl);
1792 if(SUCCEEDED(hres)) {
1793 hres = to_number(ctx, r, &nr);
1794 if(SUCCEEDED(hres))
1795 ret = jsval_number(nl+nr);
1799 jsval_release(r);
1800 jsval_release(l);
1801 if(FAILED(hres))
1802 return hres;
1804 return stack_push(ctx, ret);
1807 /* ECMA-262 3rd Edition 11.6.2 */
1808 static HRESULT interp_sub(script_ctx_t *ctx)
1810 double l, r;
1811 HRESULT hres;
1813 TRACE("\n");
1815 hres = stack_pop_number(ctx, &r);
1816 if(FAILED(hres))
1817 return hres;
1819 hres = stack_pop_number(ctx, &l);
1820 if(FAILED(hres))
1821 return hres;
1823 return stack_push(ctx, jsval_number(l-r));
1826 /* ECMA-262 3rd Edition 11.5.1 */
1827 static HRESULT interp_mul(script_ctx_t *ctx)
1829 double l, r;
1830 HRESULT hres;
1832 TRACE("\n");
1834 hres = stack_pop_number(ctx, &r);
1835 if(FAILED(hres))
1836 return hres;
1838 hres = stack_pop_number(ctx, &l);
1839 if(FAILED(hres))
1840 return hres;
1842 return stack_push(ctx, jsval_number(l*r));
1845 /* ECMA-262 3rd Edition 11.5.2 */
1846 static HRESULT interp_div(script_ctx_t *ctx)
1848 double l, r;
1849 HRESULT hres;
1851 TRACE("\n");
1853 hres = stack_pop_number(ctx, &r);
1854 if(FAILED(hres))
1855 return hres;
1857 hres = stack_pop_number(ctx, &l);
1858 if(FAILED(hres))
1859 return hres;
1861 return stack_push(ctx, jsval_number(l/r));
1864 /* ECMA-262 3rd Edition 11.5.3 */
1865 static HRESULT interp_mod(script_ctx_t *ctx)
1867 double l, r;
1868 HRESULT hres;
1870 TRACE("\n");
1872 hres = stack_pop_number(ctx, &r);
1873 if(FAILED(hres))
1874 return hres;
1876 hres = stack_pop_number(ctx, &l);
1877 if(FAILED(hres))
1878 return hres;
1880 return stack_push(ctx, jsval_number(fmod(l, r)));
1883 /* ECMA-262 3rd Edition 11.4.2 */
1884 static HRESULT interp_delete(script_ctx_t *ctx)
1886 jsval_t objv, namev;
1887 IDispatch *obj;
1888 jsstr_t *name;
1889 BOOL ret;
1890 HRESULT hres;
1892 TRACE("\n");
1894 namev = stack_pop(ctx);
1895 objv = stack_pop(ctx);
1897 hres = to_object(ctx, objv, &obj);
1898 jsval_release(objv);
1899 if(FAILED(hres)) {
1900 jsval_release(namev);
1901 return hres;
1904 hres = to_string(ctx, namev, &name);
1905 jsval_release(namev);
1906 if(FAILED(hres)) {
1907 IDispatch_Release(obj);
1908 return hres;
1911 hres = disp_delete_name(ctx, obj, name, &ret);
1912 IDispatch_Release(obj);
1913 jsstr_release(name);
1914 if(FAILED(hres))
1915 return hres;
1917 return stack_push(ctx, jsval_bool(ret));
1920 /* ECMA-262 3rd Edition 11.4.2 */
1921 static HRESULT interp_delete_ident(script_ctx_t *ctx)
1923 const BSTR arg = get_op_bstr(ctx, 0);
1924 exprval_t exprval;
1925 BOOL ret;
1926 HRESULT hres;
1928 TRACE("%s\n", debugstr_w(arg));
1930 hres = identifier_eval(ctx, arg, &exprval);
1931 if(FAILED(hres))
1932 return hres;
1934 switch(exprval.type) {
1935 case EXPRVAL_STACK_REF:
1936 ret = FALSE;
1937 break;
1938 case EXPRVAL_IDREF:
1939 hres = disp_delete(exprval.u.idref.disp, exprval.u.idref.id, &ret);
1940 IDispatch_Release(exprval.u.idref.disp);
1941 if(FAILED(hres))
1942 return hres;
1943 break;
1944 case EXPRVAL_INVALID:
1945 ret = TRUE;
1946 break;
1947 default:
1948 FIXME("Unsupported exprval\n");
1949 exprval_release(&exprval);
1950 return E_NOTIMPL;
1954 return stack_push(ctx, jsval_bool(ret));
1957 /* ECMA-262 3rd Edition 11.4.2 */
1958 static HRESULT interp_void(script_ctx_t *ctx)
1960 TRACE("\n");
1962 stack_popn(ctx, 1);
1963 return stack_push(ctx, jsval_undefined());
1966 /* ECMA-262 3rd Edition 11.4.3 */
1967 static HRESULT typeof_string(jsval_t v, const WCHAR **ret)
1969 switch(jsval_type(v)) {
1970 case JSV_UNDEFINED:
1971 *ret = L"undefined";
1972 break;
1973 case JSV_NULL:
1974 *ret = L"object";
1975 break;
1976 case JSV_OBJECT: {
1977 jsdisp_t *dispex;
1979 if(get_object(v) && (dispex = iface_to_jsdisp(get_object(v)))) {
1980 *ret = is_class(dispex, JSCLASS_FUNCTION) ? L"function" : L"object";
1981 jsdisp_release(dispex);
1982 }else {
1983 *ret = L"object";
1985 break;
1987 case JSV_STRING:
1988 *ret = L"string";
1989 break;
1990 case JSV_NUMBER:
1991 *ret = L"number";
1992 break;
1993 case JSV_BOOL:
1994 *ret = L"boolean";
1995 break;
1996 case JSV_VARIANT:
1997 FIXME("unhandled variant %s\n", debugstr_variant(get_variant(v)));
1998 return E_NOTIMPL;
2001 return S_OK;
2004 /* ECMA-262 3rd Edition 11.4.3 */
2005 static HRESULT interp_typeofid(script_ctx_t *ctx)
2007 const WCHAR *ret;
2008 exprval_t ref;
2009 jsval_t v;
2010 HRESULT hres;
2012 TRACE("\n");
2014 if(!stack_pop_exprval(ctx, &ref))
2015 return stack_push(ctx, jsval_string(jsstr_undefined()));
2017 hres = exprval_propget(ctx, &ref, &v);
2018 exprval_release(&ref);
2019 if(FAILED(hres))
2020 return stack_push_string(ctx, L"unknown");
2022 hres = typeof_string(v, &ret);
2023 jsval_release(v);
2024 if(FAILED(hres))
2025 return hres;
2027 return stack_push_string(ctx, ret);
2030 /* ECMA-262 3rd Edition 11.4.3 */
2031 static HRESULT interp_typeofident(script_ctx_t *ctx)
2033 const BSTR arg = get_op_bstr(ctx, 0);
2034 exprval_t exprval;
2035 const WCHAR *ret;
2036 jsval_t v;
2037 HRESULT hres;
2039 TRACE("%s\n", debugstr_w(arg));
2041 hres = identifier_eval(ctx, arg, &exprval);
2042 if(FAILED(hres))
2043 return hres;
2045 if(exprval.type == EXPRVAL_INVALID)
2046 return stack_push(ctx, jsval_string(jsstr_undefined()));
2048 hres = exprval_to_value(ctx, &exprval, &v);
2049 if(FAILED(hres))
2050 return hres;
2052 hres = typeof_string(v, &ret);
2053 jsval_release(v);
2054 if(FAILED(hres))
2055 return hres;
2057 return stack_push_string(ctx, ret);
2060 /* ECMA-262 3rd Edition 11.4.3 */
2061 static HRESULT interp_typeof(script_ctx_t *ctx)
2063 const WCHAR *ret;
2064 jsval_t v;
2065 HRESULT hres;
2067 TRACE("\n");
2069 v = stack_pop(ctx);
2070 hres = typeof_string(v, &ret);
2071 jsval_release(v);
2072 if(FAILED(hres))
2073 return hres;
2075 return stack_push_string(ctx, ret);
2078 /* ECMA-262 3rd Edition 11.4.7 */
2079 static HRESULT interp_minus(script_ctx_t *ctx)
2081 double n;
2082 HRESULT hres;
2084 TRACE("\n");
2086 hres = stack_pop_number(ctx, &n);
2087 if(FAILED(hres))
2088 return hres;
2090 return stack_push(ctx, jsval_number(-n));
2093 /* ECMA-262 3rd Edition 11.4.6 */
2094 static HRESULT interp_tonum(script_ctx_t *ctx)
2096 jsval_t v;
2097 double n;
2098 HRESULT hres;
2100 TRACE("\n");
2102 v = stack_pop(ctx);
2103 hres = to_number(ctx, v, &n);
2104 jsval_release(v);
2105 if(FAILED(hres))
2106 return hres;
2108 return stack_push(ctx, jsval_number(n));
2111 /* ECMA-262 3rd Edition 11.3.1 */
2112 static HRESULT interp_postinc(script_ctx_t *ctx)
2114 const int arg = get_op_int(ctx, 0);
2115 exprval_t ref;
2116 jsval_t v;
2117 HRESULT hres;
2119 TRACE("%d\n", arg);
2121 if(!stack_pop_exprval(ctx, &ref))
2122 return JS_E_OBJECT_EXPECTED;
2124 hres = exprval_propget(ctx, &ref, &v);
2125 if(SUCCEEDED(hres)) {
2126 double n;
2128 hres = to_number(ctx, v, &n);
2129 if(SUCCEEDED(hres))
2130 hres = exprval_propput(ctx, &ref, jsval_number(n+(double)arg));
2131 if(FAILED(hres))
2132 jsval_release(v);
2134 exprval_release(&ref);
2135 if(FAILED(hres))
2136 return hres;
2138 return stack_push(ctx, v);
2141 /* ECMA-262 3rd Edition 11.4.4, 11.4.5 */
2142 static HRESULT interp_preinc(script_ctx_t *ctx)
2144 const int arg = get_op_int(ctx, 0);
2145 exprval_t ref;
2146 double ret;
2147 jsval_t v;
2148 HRESULT hres;
2150 TRACE("%d\n", arg);
2152 if(!stack_pop_exprval(ctx, &ref))
2153 return JS_E_OBJECT_EXPECTED;
2155 hres = exprval_propget(ctx, &ref, &v);
2156 if(SUCCEEDED(hres)) {
2157 double n;
2159 hres = to_number(ctx, v, &n);
2160 jsval_release(v);
2161 if(SUCCEEDED(hres)) {
2162 ret = n+(double)arg;
2163 hres = exprval_propput(ctx, &ref, jsval_number(ret));
2166 exprval_release(&ref);
2167 if(FAILED(hres))
2168 return hres;
2170 return stack_push(ctx, jsval_number(ret));
2173 /* ECMA-262 3rd Edition 11.9.3 */
2174 static HRESULT equal_values(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL *ret)
2176 if(jsval_type(lval) == jsval_type(rval) || (is_number(lval) && is_number(rval)))
2177 return jsval_strict_equal(lval, rval, ret);
2179 /* FIXME: NULL disps should be handled in more general way */
2180 if(is_object_instance(lval) && !get_object(lval))
2181 return equal_values(ctx, jsval_null(), rval, ret);
2182 if(is_object_instance(rval) && !get_object(rval))
2183 return equal_values(ctx, lval, jsval_null(), ret);
2185 if((is_null(lval) && is_undefined(rval)) || (is_undefined(lval) && is_null(rval))) {
2186 *ret = TRUE;
2187 return S_OK;
2190 if(is_string(lval) && is_number(rval)) {
2191 double n;
2192 HRESULT hres;
2194 hres = to_number(ctx, lval, &n);
2195 if(FAILED(hres))
2196 return hres;
2198 /* FIXME: optimize */
2199 return equal_values(ctx, jsval_number(n), rval, ret);
2202 if(is_string(rval) && is_number(lval)) {
2203 double n;
2204 HRESULT hres;
2206 hres = to_number(ctx, rval, &n);
2207 if(FAILED(hres))
2208 return hres;
2210 /* FIXME: optimize */
2211 return equal_values(ctx, lval, jsval_number(n), ret);
2214 if(is_bool(rval))
2215 return equal_values(ctx, lval, jsval_number(get_bool(rval) ? 1 : 0), ret);
2217 if(is_bool(lval))
2218 return equal_values(ctx, jsval_number(get_bool(lval) ? 1 : 0), rval, ret);
2221 if(is_object_instance(rval) && (is_string(lval) || is_number(lval))) {
2222 jsval_t prim;
2223 HRESULT hres;
2225 hres = to_primitive(ctx, rval, &prim, NO_HINT);
2226 if(FAILED(hres))
2227 return hres;
2229 hres = equal_values(ctx, lval, prim, ret);
2230 jsval_release(prim);
2231 return hres;
2235 if(is_object_instance(lval) && (is_string(rval) || is_number(rval))) {
2236 jsval_t prim;
2237 HRESULT hres;
2239 hres = to_primitive(ctx, lval, &prim, NO_HINT);
2240 if(FAILED(hres))
2241 return hres;
2243 hres = equal_values(ctx, prim, rval, ret);
2244 jsval_release(prim);
2245 return hres;
2249 *ret = FALSE;
2250 return S_OK;
2253 /* ECMA-262 3rd Edition 11.9.1 */
2254 static HRESULT interp_eq(script_ctx_t *ctx)
2256 jsval_t l, r;
2257 BOOL b;
2258 HRESULT hres;
2260 r = stack_pop(ctx);
2261 l = stack_pop(ctx);
2263 TRACE("%s == %s\n", debugstr_jsval(l), debugstr_jsval(r));
2265 hres = equal_values(ctx, l, r, &b);
2266 jsval_release(l);
2267 jsval_release(r);
2268 if(FAILED(hres))
2269 return hres;
2271 return stack_push(ctx, jsval_bool(b));
2274 /* ECMA-262 3rd Edition 11.9.2 */
2275 static HRESULT interp_neq(script_ctx_t *ctx)
2277 jsval_t l, r;
2278 BOOL b;
2279 HRESULT hres;
2281 r = stack_pop(ctx);
2282 l = stack_pop(ctx);
2284 TRACE("%s != %s\n", debugstr_jsval(l), debugstr_jsval(r));
2286 hres = equal_values(ctx, l, r, &b);
2287 jsval_release(l);
2288 jsval_release(r);
2289 if(FAILED(hres))
2290 return hres;
2292 return stack_push(ctx, jsval_bool(!b));
2295 /* ECMA-262 3rd Edition 11.9.4 */
2296 static HRESULT interp_eq2(script_ctx_t *ctx)
2298 jsval_t l, r;
2299 BOOL b;
2300 HRESULT hres;
2302 r = stack_pop(ctx);
2303 l = stack_pop(ctx);
2305 TRACE("%s === %s\n", debugstr_jsval(l), debugstr_jsval(r));
2307 hres = jsval_strict_equal(r, l, &b);
2308 jsval_release(l);
2309 jsval_release(r);
2310 if(FAILED(hres))
2311 return hres;
2313 return stack_push(ctx, jsval_bool(b));
2316 /* ECMA-262 3rd Edition 11.9.5 */
2317 static HRESULT interp_neq2(script_ctx_t *ctx)
2319 jsval_t l, r;
2320 BOOL b;
2321 HRESULT hres;
2323 TRACE("\n");
2325 r = stack_pop(ctx);
2326 l = stack_pop(ctx);
2328 hres = jsval_strict_equal(r, l, &b);
2329 jsval_release(l);
2330 jsval_release(r);
2331 if(FAILED(hres))
2332 return hres;
2334 return stack_push(ctx, jsval_bool(!b));
2337 /* ECMA-262 3rd Edition 11.8.5 */
2338 static HRESULT less_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL greater, BOOL *ret)
2340 double ln, rn;
2341 jsval_t l, r;
2342 HRESULT hres;
2344 hres = to_primitive(ctx, lval, &l, NO_HINT);
2345 if(FAILED(hres))
2346 return hres;
2348 hres = to_primitive(ctx, rval, &r, NO_HINT);
2349 if(FAILED(hres)) {
2350 jsval_release(l);
2351 return hres;
2354 if(is_string(l) && is_string(r)) {
2355 *ret = (jsstr_cmp(get_string(l), get_string(r)) < 0) ^ greater;
2356 jsstr_release(get_string(l));
2357 jsstr_release(get_string(r));
2358 return S_OK;
2361 hres = to_number(ctx, l, &ln);
2362 jsval_release(l);
2363 if(SUCCEEDED(hres))
2364 hres = to_number(ctx, r, &rn);
2365 jsval_release(r);
2366 if(FAILED(hres))
2367 return hres;
2369 *ret = !isnan(ln) && !isnan(rn) && ((ln < rn) ^ greater);
2370 return S_OK;
2373 /* ECMA-262 3rd Edition 11.8.1 */
2374 static HRESULT interp_lt(script_ctx_t *ctx)
2376 jsval_t l, r;
2377 BOOL b;
2378 HRESULT hres;
2380 r = stack_pop(ctx);
2381 l = stack_pop(ctx);
2383 TRACE("%s < %s\n", debugstr_jsval(l), debugstr_jsval(r));
2385 hres = less_eval(ctx, l, r, FALSE, &b);
2386 jsval_release(l);
2387 jsval_release(r);
2388 if(FAILED(hres))
2389 return hres;
2391 return stack_push(ctx, jsval_bool(b));
2394 /* ECMA-262 3rd Edition 11.8.1 */
2395 static HRESULT interp_lteq(script_ctx_t *ctx)
2397 jsval_t l, r;
2398 BOOL b;
2399 HRESULT hres;
2401 r = stack_pop(ctx);
2402 l = stack_pop(ctx);
2404 TRACE("%s <= %s\n", debugstr_jsval(l), debugstr_jsval(r));
2406 hres = less_eval(ctx, r, l, TRUE, &b);
2407 jsval_release(l);
2408 jsval_release(r);
2409 if(FAILED(hres))
2410 return hres;
2412 return stack_push(ctx, jsval_bool(b));
2415 /* ECMA-262 3rd Edition 11.8.2 */
2416 static HRESULT interp_gt(script_ctx_t *ctx)
2418 jsval_t l, r;
2419 BOOL b;
2420 HRESULT hres;
2422 r = stack_pop(ctx);
2423 l = stack_pop(ctx);
2425 TRACE("%s > %s\n", debugstr_jsval(l), debugstr_jsval(r));
2427 hres = less_eval(ctx, r, l, FALSE, &b);
2428 jsval_release(l);
2429 jsval_release(r);
2430 if(FAILED(hres))
2431 return hres;
2433 return stack_push(ctx, jsval_bool(b));
2436 /* ECMA-262 3rd Edition 11.8.4 */
2437 static HRESULT interp_gteq(script_ctx_t *ctx)
2439 jsval_t l, r;
2440 BOOL b;
2441 HRESULT hres;
2443 r = stack_pop(ctx);
2444 l = stack_pop(ctx);
2446 TRACE("%s >= %s\n", debugstr_jsval(l), debugstr_jsval(r));
2448 hres = less_eval(ctx, l, r, TRUE, &b);
2449 jsval_release(l);
2450 jsval_release(r);
2451 if(FAILED(hres))
2452 return hres;
2454 return stack_push(ctx, jsval_bool(b));
2457 /* ECMA-262 3rd Edition 11.4.8 */
2458 static HRESULT interp_bneg(script_ctx_t *ctx)
2460 jsval_t v;
2461 INT i;
2462 HRESULT hres;
2464 TRACE("\n");
2466 v = stack_pop(ctx);
2467 hres = to_int32(ctx, v, &i);
2468 jsval_release(v);
2469 if(FAILED(hres))
2470 return hres;
2472 return stack_push(ctx, jsval_number(~i));
2475 /* ECMA-262 3rd Edition 11.4.9 */
2476 static HRESULT interp_neg(script_ctx_t *ctx)
2478 jsval_t v;
2479 BOOL b;
2480 HRESULT hres;
2482 TRACE("\n");
2484 v = stack_pop(ctx);
2485 hres = to_boolean(v, &b);
2486 jsval_release(v);
2487 if(FAILED(hres))
2488 return hres;
2490 return stack_push(ctx, jsval_bool(!b));
2493 /* ECMA-262 3rd Edition 11.7.1 */
2494 static HRESULT interp_lshift(script_ctx_t *ctx)
2496 DWORD r;
2497 INT l;
2498 HRESULT hres;
2500 hres = stack_pop_uint(ctx, &r);
2501 if(FAILED(hres))
2502 return hres;
2504 hres = stack_pop_int(ctx, &l);
2505 if(FAILED(hres))
2506 return hres;
2508 return stack_push(ctx, jsval_number(l << (r&0x1f)));
2511 /* ECMA-262 3rd Edition 11.7.2 */
2512 static HRESULT interp_rshift(script_ctx_t *ctx)
2514 DWORD r;
2515 INT l;
2516 HRESULT hres;
2518 hres = stack_pop_uint(ctx, &r);
2519 if(FAILED(hres))
2520 return hres;
2522 hres = stack_pop_int(ctx, &l);
2523 if(FAILED(hres))
2524 return hres;
2526 return stack_push(ctx, jsval_number(l >> (r&0x1f)));
2529 /* ECMA-262 3rd Edition 11.7.3 */
2530 static HRESULT interp_rshift2(script_ctx_t *ctx)
2532 DWORD r, l;
2533 HRESULT hres;
2535 hres = stack_pop_uint(ctx, &r);
2536 if(FAILED(hres))
2537 return hres;
2539 hres = stack_pop_uint(ctx, &l);
2540 if(FAILED(hres))
2541 return hres;
2543 return stack_push(ctx, jsval_number(l >> (r&0x1f)));
2546 /* ECMA-262 3rd Edition 9.8 */
2547 static HRESULT interp_to_string(script_ctx_t *ctx)
2549 jsstr_t *str;
2550 jsval_t v;
2551 HRESULT hres;
2553 v = stack_pop(ctx);
2554 TRACE("%s\n", debugstr_jsval(v));
2555 hres = to_string(ctx, v, &str);
2556 jsval_release(v);
2557 if(FAILED(hres)) {
2558 WARN("failed %08x\n", hres);
2559 return hres;
2562 return stack_push(ctx, jsval_string(str));
2565 /* ECMA-262 3rd Edition 11.13.1 */
2566 static HRESULT interp_assign(script_ctx_t *ctx)
2568 exprval_t ref;
2569 jsval_t v;
2570 HRESULT hres;
2572 TRACE("\n");
2574 v = stack_pop(ctx);
2576 if(!stack_pop_exprval(ctx, &ref)) {
2577 jsval_release(v);
2578 return JS_E_ILLEGAL_ASSIGN;
2581 hres = exprval_propput(ctx, &ref, v);
2582 exprval_release(&ref);
2583 if(FAILED(hres)) {
2584 jsval_release(v);
2585 return hres;
2588 return stack_push(ctx, v);
2591 /* ECMA-262 3rd Edition 11.13.1 */
2592 static HRESULT interp_set_member(script_ctx_t *ctx)
2594 jsval_t objv, namev, value;
2595 const WCHAR *name;
2596 IDispatch *obj;
2597 HRESULT hres;
2599 value = stack_pop(ctx);
2600 namev = stack_pop(ctx);
2601 assert(is_string(namev));
2602 objv = stack_pop(ctx);
2604 TRACE("%s.%s = %s\n", debugstr_jsval(objv), debugstr_jsval(namev), debugstr_jsval(value));
2606 hres = to_object(ctx, objv, &obj);
2607 jsval_release(objv);
2608 if(SUCCEEDED(hres) && !(name = jsstr_flatten(get_string(namev)))) {
2609 IDispatch_Release(obj);
2610 hres = E_OUTOFMEMORY;
2612 if(SUCCEEDED(hres)) {
2613 hres = disp_propput_name(ctx, obj, name, value);
2614 IDispatch_Release(obj);
2615 jsstr_release(get_string(namev));
2617 if(FAILED(hres)) {
2618 WARN("failed %08x\n", hres);
2619 jsval_release(value);
2620 return hres;
2623 return stack_push(ctx, value);
2626 /* JScript extension */
2627 static HRESULT interp_assign_call(script_ctx_t *ctx)
2629 const unsigned argc = get_op_uint(ctx, 0);
2630 exprval_t ref;
2631 jsval_t v;
2632 HRESULT hres;
2634 TRACE("%u\n", argc);
2636 if(!stack_topn_exprval(ctx, argc+1, &ref))
2637 return JS_E_ILLEGAL_ASSIGN;
2639 hres = exprval_call(ctx, &ref, DISPATCH_PROPERTYPUT, argc+1, stack_args(ctx, argc+1), NULL);
2640 if(FAILED(hres))
2641 return hres;
2643 v = stack_pop(ctx);
2644 stack_popn(ctx, argc+2);
2645 return stack_push(ctx, v);
2648 static HRESULT interp_undefined(script_ctx_t *ctx)
2650 TRACE("\n");
2652 return stack_push(ctx, jsval_undefined());
2655 static HRESULT interp_jmp(script_ctx_t *ctx)
2657 const unsigned arg = get_op_uint(ctx, 0);
2659 TRACE("%u\n", arg);
2661 jmp_abs(ctx, arg);
2662 return S_OK;
2665 static HRESULT interp_jmp_z(script_ctx_t *ctx)
2667 const unsigned arg = get_op_uint(ctx, 0);
2668 BOOL b;
2669 jsval_t v;
2670 HRESULT hres;
2672 TRACE("\n");
2674 v = stack_pop(ctx);
2675 hres = to_boolean(v, &b);
2676 jsval_release(v);
2677 if(FAILED(hres))
2678 return hres;
2680 if(b)
2681 jmp_next(ctx);
2682 else
2683 jmp_abs(ctx, arg);
2684 return S_OK;
2687 static HRESULT interp_pop(script_ctx_t *ctx)
2689 const unsigned arg = get_op_uint(ctx, 0);
2691 TRACE("%u\n", arg);
2693 stack_popn(ctx, arg);
2694 return S_OK;
2697 static HRESULT interp_ret(script_ctx_t *ctx)
2699 const unsigned clear_ret = get_op_uint(ctx, 0);
2700 call_frame_t *frame = ctx->call_ctx;
2702 TRACE("\n");
2704 if(clear_ret)
2705 jsval_release(steal_ret(frame));
2707 if((frame->flags & EXEC_CONSTRUCTOR) && !is_object_instance(frame->ret)) {
2708 jsval_release(frame->ret);
2709 IDispatch_AddRef(frame->this_obj);
2710 frame->ret = jsval_disp(frame->this_obj);
2713 jmp_abs(ctx, -1);
2714 return S_OK;
2717 static HRESULT interp_setret(script_ctx_t *ctx)
2719 call_frame_t *frame = ctx->call_ctx;
2721 TRACE("\n");
2723 jsval_release(frame->ret);
2724 frame->ret = stack_pop(ctx);
2725 return S_OK;
2728 static HRESULT interp_push_acc(script_ctx_t *ctx)
2730 HRESULT hres;
2732 TRACE("\n");
2734 hres = stack_push(ctx, ctx->acc);
2735 if(SUCCEEDED(hres))
2736 ctx->acc = jsval_undefined();
2737 return hres;
2740 typedef HRESULT (*op_func_t)(script_ctx_t*);
2742 static const op_func_t op_funcs[] = {
2743 #define X(x,a,b,c) interp_##x,
2744 OP_LIST
2745 #undef X
2748 static const unsigned op_move[] = {
2749 #define X(a,x,b,c) x,
2750 OP_LIST
2751 #undef X
2754 static void pop_call_frame(script_ctx_t *ctx)
2756 call_frame_t *frame = ctx->call_ctx;
2758 frame->stack_base -= frame->pop_locals + frame->pop_variables;
2760 assert(frame->scope == frame->base_scope);
2762 /* If current scope will be kept alive, we need to transfer local variables to its variable object. */
2763 if(frame->scope && frame->scope->ref > 1) {
2764 HRESULT hres = detach_variable_object(ctx, frame, TRUE);
2765 if(FAILED(hres))
2766 ERR("Failed to detach variable object: %08x\n", hres);
2769 if(frame->arguments_obj)
2770 detach_arguments_object(frame->arguments_obj);
2771 if(frame->scope)
2772 scope_release(frame->scope);
2774 if(frame->pop_variables)
2775 stack_popn(ctx, frame->pop_variables);
2776 stack_popn(ctx, frame->pop_locals);
2778 ctx->call_ctx = frame->prev_frame;
2780 if(frame->function_instance)
2781 jsdisp_release(frame->function_instance);
2782 if(frame->variable_obj)
2783 jsdisp_release(frame->variable_obj);
2784 if(frame->this_obj)
2785 IDispatch_Release(frame->this_obj);
2786 jsval_release(frame->ret);
2787 release_bytecode(frame->bytecode);
2788 heap_free(frame);
2791 static void print_backtrace(script_ctx_t *ctx)
2793 unsigned depth = 0, i, line, char_pos;
2794 call_frame_t *frame;
2796 for(frame = ctx->call_ctx; frame; frame = frame->prev_frame) {
2797 WARN("%u\t", depth);
2798 depth++;
2800 if(frame->this_obj)
2801 WARN("%p->", frame->this_obj);
2802 WARN("%s(", frame->function->name ? debugstr_w(frame->function->name) : "[unnamed]");
2803 if(frame->base_scope && frame->base_scope->frame) {
2804 for(i=0; i < frame->argc; i++) {
2805 if(i < frame->function->param_cnt)
2806 WARN("%s%s=%s", i ? ", " : "", debugstr_w(frame->function->params[i]),
2807 debugstr_jsval(ctx->stack[local_off(frame, -i-1)]));
2808 else
2809 WARN("%s%s", i ? ", " : "", debugstr_jsval(ctx->stack[local_off(frame, -i-1)]));
2811 }else {
2812 WARN("[detached frame]");
2814 line = get_location_line(frame->bytecode, frame->bytecode->instrs[frame->ip].loc, &char_pos);
2815 WARN(") context %s line %u char %u\n", wine_dbgstr_longlong(frame->bytecode->source_context), line, char_pos);
2817 if(!(frame->flags & EXEC_RETURN_TO_INTERP)) {
2818 WARN("%u\t[native code]\n", depth);
2819 depth++;
2824 static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres)
2826 except_frame_t *except_frame;
2827 jsexcept_t *ei = ctx->ei;
2828 call_frame_t *frame;
2829 jsval_t except_val;
2830 unsigned catch_off;
2831 HRESULT hres;
2833 if(WARN_ON(jscript)) {
2834 jsdisp_t *error_obj;
2835 jsval_t msg;
2837 WARN("Exception %08x %s", exception_hres, debugstr_jsval(ei->valid_value ? ei->value : jsval_undefined()));
2838 if(ei->valid_value && jsval_type(ei->value) == JSV_OBJECT) {
2839 error_obj = to_jsdisp(get_object(ei->value));
2840 if(error_obj) {
2841 hres = jsdisp_propget_name(error_obj, L"message", &msg);
2842 if(SUCCEEDED(hres)) {
2843 WARN(" (message %s)", debugstr_jsval(msg));
2844 jsval_release(msg);
2848 WARN(" in:\n");
2850 print_backtrace(ctx);
2853 frame = ctx->call_ctx;
2854 if(exception_hres != DISP_E_EXCEPTION)
2855 throw_error(ctx, exception_hres, NULL);
2856 set_error_location(ei, frame->bytecode, frame->bytecode->instrs[frame->ip].loc, IDS_RUNTIME_ERROR, NULL);
2858 while(!frame->except_frame) {
2859 DWORD flags;
2861 while(frame->scope != frame->base_scope)
2862 scope_pop(&frame->scope);
2864 stack_popn(ctx, ctx->stack_top-frame->stack_base);
2866 flags = frame->flags;
2867 pop_call_frame(ctx);
2868 if(!(flags & EXEC_RETURN_TO_INTERP))
2869 return DISP_E_EXCEPTION;
2870 frame = ctx->call_ctx;
2873 except_frame = frame->except_frame;
2874 catch_off = except_frame->catch_off;
2876 assert(except_frame->stack_top <= ctx->stack_top);
2877 stack_popn(ctx, ctx->stack_top - except_frame->stack_top);
2879 while(except_frame->scope != frame->scope)
2880 scope_pop(&frame->scope);
2882 frame->ip = catch_off ? catch_off : except_frame->finally_off;
2883 assert(!catch_off || frame->bytecode->instrs[frame->ip].op == OP_enter_catch);
2885 if(ei->valid_value) {
2886 except_val = ctx->ei->value;
2887 ei->valid_value = FALSE;
2888 }else {
2889 jsdisp_t *err;
2890 if(!(err = create_builtin_error(ctx)))
2891 return E_OUTOFMEMORY;
2892 except_val = jsval_obj(err);
2895 /* keep current except_frame if we're entering catch block with finally block associated */
2896 if(catch_off && except_frame->finally_off) {
2897 except_frame->catch_off = 0;
2898 }else {
2899 frame->except_frame = except_frame->next;
2900 heap_free(except_frame);
2903 hres = stack_push(ctx, except_val);
2904 if(FAILED(hres))
2905 return hres;
2907 if(!catch_off)
2908 hres = stack_push(ctx, jsval_bool(FALSE));
2909 return hres;
2912 static HRESULT enter_bytecode(script_ctx_t *ctx, jsval_t *r)
2914 call_frame_t *frame;
2915 jsop_t op;
2916 HRESULT hres = S_OK;
2918 TRACE("\n");
2920 while(1) {
2921 frame = ctx->call_ctx;
2922 op = frame->bytecode->instrs[frame->ip].op;
2923 hres = op_funcs[op](ctx);
2924 if(FAILED(hres)) {
2925 hres = unwind_exception(ctx, hres);
2926 if(FAILED(hres))
2927 return hres;
2928 }else if(frame->ip == -1) {
2929 const DWORD return_to_interp = frame->flags & EXEC_RETURN_TO_INTERP;
2931 assert(ctx->stack_top == frame->stack_base);
2932 assert(frame->scope == frame->base_scope);
2934 if(return_to_interp) {
2935 jsval_release(ctx->acc);
2936 ctx->acc = steal_ret(frame);
2937 }else if(r) {
2938 *r = steal_ret(frame);
2940 pop_call_frame(ctx);
2941 if(!return_to_interp)
2942 break;
2943 }else {
2944 frame->ip += op_move[op];
2948 return S_OK;
2951 static HRESULT bind_event_target(script_ctx_t *ctx, function_code_t *func, jsdisp_t *func_obj)
2953 IBindEventHandler *target;
2954 exprval_t exprval;
2955 IDispatch *disp;
2956 jsval_t v;
2957 HRESULT hres;
2959 hres = identifier_eval(ctx, func->event_target, &exprval);
2960 if(FAILED(hres))
2961 return hres;
2963 hres = exprval_to_value(ctx, &exprval, &v);
2964 if(FAILED(hres))
2965 return hres;
2967 if(!is_object_instance(v)) {
2968 FIXME("Can't bind to %s\n", debugstr_jsval(v));
2969 jsval_release(v);
2972 disp = get_object(v);
2973 hres = IDispatch_QueryInterface(disp, &IID_IBindEventHandler, (void**)&target);
2974 if(SUCCEEDED(hres)) {
2975 hres = IBindEventHandler_BindHandler(target, func->name, (IDispatch*)&func_obj->IDispatchEx_iface);
2976 IBindEventHandler_Release(target);
2977 if(FAILED(hres))
2978 WARN("BindEvent failed: %08x\n", hres);
2979 }else {
2980 FIXME("No IBindEventHandler, not yet supported binding\n");
2983 IDispatch_Release(disp);
2984 return hres;
2987 static HRESULT setup_scope(script_ctx_t *ctx, call_frame_t *frame, scope_chain_t *scope_chain, jsdisp_t *variable_object, unsigned argc, jsval_t *argv)
2989 const unsigned orig_stack = ctx->stack_top;
2990 scope_chain_t *scope;
2991 unsigned i;
2992 jsval_t v;
2993 HRESULT hres;
2995 /* If arguments are already on the stack, we may use them. */
2996 if(argv + argc == ctx->stack + ctx->stack_top) {
2997 frame->arguments_off = argv - ctx->stack;
2998 i = argc;
2999 }else {
3000 frame->arguments_off = ctx->stack_top;
3001 for(i = 0; i < argc; i++) {
3002 hres = jsval_copy(argv[i], &v);
3003 if(SUCCEEDED(hres))
3004 hres = stack_push(ctx, v);
3005 if(FAILED(hres)) {
3006 stack_popn(ctx, i);
3007 return hres;
3012 /* If fewer than declared arguments were passed, fill remaining with undefined value. */
3013 for(; i < frame->function->param_cnt; i++) {
3014 hres = stack_push(ctx, jsval_undefined());
3015 if(FAILED(hres)) {
3016 stack_popn(ctx, ctx->stack_top - orig_stack);
3017 return hres;
3021 frame->pop_locals = ctx->stack_top - orig_stack;
3023 frame->variables_off = ctx->stack_top;
3025 for(i = 0; i < frame->function->var_cnt; i++) {
3026 hres = stack_push(ctx, jsval_undefined());
3027 if(FAILED(hres)) {
3028 stack_popn(ctx, ctx->stack_top - orig_stack);
3029 return hres;
3033 frame->pop_variables = i;
3035 hres = scope_push(scope_chain, variable_object, to_disp(variable_object), &scope);
3036 if(FAILED(hres)) {
3037 stack_popn(ctx, ctx->stack_top - orig_stack);
3038 return hres;
3041 for(i = 0; i < frame->function->func_cnt; i++) {
3042 if(frame->function->funcs[i].name && !frame->function->funcs[i].event_target) {
3043 jsdisp_t *func_obj;
3044 unsigned off;
3046 hres = create_source_function(ctx, frame->bytecode, frame->function->funcs+i, scope, &func_obj);
3047 if(FAILED(hres)) {
3048 stack_popn(ctx, ctx->stack_top - orig_stack);
3049 scope_release(scope);
3050 return hres;
3053 off = local_off(frame, frame->function->funcs[i].local_ref);
3054 jsval_release(ctx->stack[off]);
3055 ctx->stack[off] = jsval_obj(func_obj);
3059 scope->frame = frame;
3060 frame->base_scope = frame->scope = scope;
3061 return S_OK;
3064 HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, function_code_t *function, scope_chain_t *scope,
3065 IDispatch *this_obj, jsdisp_t *function_instance, unsigned argc, jsval_t *argv, jsval_t *r)
3067 jsdisp_t *variable_obj;
3068 call_frame_t *frame;
3069 unsigned i;
3070 HRESULT hres;
3072 if(!ctx->stack) {
3073 ctx->stack = heap_alloc(stack_size * sizeof(*ctx->stack));
3074 if(!ctx->stack)
3075 return E_OUTOFMEMORY;
3078 if(bytecode->named_item) {
3079 if(!bytecode->named_item->script_obj) {
3080 hres = create_named_item_script_obj(ctx, bytecode->named_item);
3081 if(FAILED(hres)) return hres;
3085 if(!ctx->ei->enter_notified) {
3086 ctx->ei->enter_notified = TRUE;
3087 IActiveScriptSite_OnEnterScript(ctx->site);
3090 for(i = 0; i < function->func_cnt; i++) {
3091 jsdisp_t *func_obj;
3093 if(!function->funcs[i].event_target)
3094 continue;
3096 hres = create_source_function(ctx, bytecode, function->funcs+i, scope, &func_obj);
3097 if(FAILED(hres))
3098 return hres;
3100 hres = bind_event_target(ctx, function->funcs+i, func_obj);
3101 jsdisp_release(func_obj);
3102 if(FAILED(hres))
3103 return hres;
3106 if((flags & EXEC_EVAL) && ctx->call_ctx) {
3107 variable_obj = jsdisp_addref(ctx->call_ctx->variable_obj);
3108 }else if(!(flags & (EXEC_GLOBAL | EXEC_EVAL))) {
3109 hres = create_dispex(ctx, NULL, NULL, &variable_obj);
3110 if(FAILED(hres)) return hres;
3111 }else if(bytecode->named_item) {
3112 variable_obj = jsdisp_addref(bytecode->named_item->script_obj);
3113 }else {
3114 variable_obj = jsdisp_addref(ctx->global);
3117 if(flags & (EXEC_GLOBAL | EXEC_EVAL)) {
3118 named_item_t *item = bytecode->named_item;
3119 DISPID id;
3121 for(i=0; i < function->var_cnt; i++) {
3122 TRACE("[%d] %s %d\n", i, debugstr_w(function->variables[i].name), function->variables[i].func_id);
3123 if(function->variables[i].func_id != -1) {
3124 jsdisp_t *func_obj;
3126 hres = create_source_function(ctx, bytecode, function->funcs+function->variables[i].func_id, scope, &func_obj);
3127 if(FAILED(hres))
3128 goto fail;
3130 hres = jsdisp_propput_name(variable_obj, function->variables[i].name, jsval_obj(func_obj));
3131 jsdisp_release(func_obj);
3132 continue;
3135 if(item && !(item->flags & SCRIPTITEM_CODEONLY)
3136 && SUCCEEDED(disp_get_id(ctx, item->disp, function->variables[i].name, function->variables[i].name, 0, &id)))
3137 continue;
3139 if(!item && (flags & EXEC_GLOBAL) && lookup_global_members(ctx, function->variables[i].name, NULL))
3140 continue;
3142 hres = jsdisp_get_id(variable_obj, function->variables[i].name, fdexNameEnsure, &id);
3143 if(FAILED(hres))
3144 goto fail;
3148 /* ECMA-262 3rd Edition 11.2.3.7 */
3149 if(this_obj) {
3150 jsdisp_t *jsthis;
3152 jsthis = iface_to_jsdisp(this_obj);
3153 if(jsthis) {
3154 if(jsthis->builtin_info->class == JSCLASS_GLOBAL || jsthis->builtin_info->class == JSCLASS_NONE)
3155 this_obj = NULL;
3156 jsdisp_release(jsthis);
3160 if(ctx->call_ctx && (flags & EXEC_EVAL)) {
3161 hres = detach_variable_object(ctx, ctx->call_ctx, FALSE);
3162 if(FAILED(hres))
3163 goto fail;
3166 frame = heap_alloc_zero(sizeof(*frame));
3167 if(!frame) {
3168 hres = E_OUTOFMEMORY;
3169 goto fail;
3172 frame->function = function;
3173 frame->ret = jsval_undefined();
3174 frame->argc = argc;
3175 frame->bytecode = bytecode_addref(bytecode);
3177 if(!(flags & (EXEC_GLOBAL|EXEC_EVAL))) {
3178 hres = setup_scope(ctx, frame, scope, variable_obj, argc, argv);
3179 if(FAILED(hres)) {
3180 release_bytecode(frame->bytecode);
3181 heap_free(frame);
3182 goto fail;
3184 }else if(scope) {
3185 frame->base_scope = frame->scope = scope_addref(scope);
3188 frame->ip = function->instr_off;
3189 frame->stack_base = ctx->stack_top;
3190 if(this_obj) {
3191 frame->this_obj = this_obj;
3192 IDispatch_AddRef(frame->this_obj);
3195 if(function_instance)
3196 frame->function_instance = jsdisp_addref(function_instance);
3198 frame->flags = flags;
3199 frame->variable_obj = variable_obj;
3201 frame->prev_frame = ctx->call_ctx;
3202 ctx->call_ctx = frame;
3204 if(flags & EXEC_RETURN_TO_INTERP) {
3206 * We're called directly from interpreter, so we may just setup call frame and return.
3207 * Already running interpreter will take care of execution.
3209 if(r)
3210 *r = jsval_undefined();
3211 return S_OK;
3214 return enter_bytecode(ctx, r);
3216 fail:
3217 jsdisp_release(variable_obj);
3218 return hres;