dbghelp: Properly fail on PDB files generated by MSVC compiler version 14.31.
[wine.git] / dlls / jscript / engine.c
blob73b9d868e0cc6bd77eb88f5ab17e9c596762ffdd
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 *r = get_object(v);
135 return S_OK;
138 hres = to_object(ctx, v, r);
139 jsval_release(v);
140 return hres;
143 static inline HRESULT stack_pop_int(script_ctx_t *ctx, INT *r)
145 return to_int32(ctx, stack_pop(ctx), r);
148 static inline HRESULT stack_pop_uint(script_ctx_t *ctx, UINT32 *r)
150 return to_uint32(ctx, stack_pop(ctx), r);
153 static inline unsigned local_off(call_frame_t *frame, int ref)
155 return ref < 0
156 ? frame->arguments_off - ref-1
157 : frame->variables_off + ref;
160 static inline BSTR local_name(call_frame_t *frame, int ref)
162 return ref < 0 ? frame->function->params[-ref-1] : frame->function->variables[ref].name;
165 /* Steals input reference even on failure. */
166 static HRESULT stack_push_exprval(script_ctx_t *ctx, exprval_t *val)
168 HRESULT hres;
170 switch(val->type) {
171 case EXPRVAL_JSVAL:
172 hres = stack_push(ctx, jsval_null());
173 if(SUCCEEDED(hres))
174 hres = stack_push(ctx, val->u.val);
175 return hres;
176 case EXPRVAL_IDREF:
177 hres = stack_push(ctx, jsval_disp(val->u.idref.disp));
178 if(SUCCEEDED(hres))
179 hres = stack_push(ctx, jsval_number(val->u.idref.id));
180 else
181 IDispatch_Release(val->u.idref.disp);
182 return hres;
183 case EXPRVAL_STACK_REF:
184 hres = stack_push(ctx, jsval_number(val->u.off));
185 if(SUCCEEDED(hres))
186 hres = stack_push(ctx, jsval_undefined());
187 return hres;
188 case EXPRVAL_INVALID:
189 hres = stack_push(ctx, jsval_undefined());
190 if(SUCCEEDED(hres))
191 hres = stack_push(ctx, jsval_number(val->u.hres));
192 return hres;
195 assert(0);
196 return E_FAIL;
199 static BOOL stack_topn_exprval(script_ctx_t *ctx, unsigned n, exprval_t *r)
201 jsval_t v = stack_topn(ctx, n+1);
203 switch(jsval_type(v)) {
204 case JSV_NUMBER: {
205 call_frame_t *frame = ctx->call_ctx;
206 scope_chain_t *scope;
207 unsigned off = get_number(v);
209 if(!frame->base_scope->frame && off >= frame->arguments_off) {
210 DISPID id;
211 BSTR name;
212 HRESULT hres = E_FAIL;
214 /* Got stack reference in deoptimized code. Need to convert it back to variable object reference. */
216 assert(off < frame->variables_off + frame->function->var_cnt);
217 if (off >= frame->variables_off)
219 name = frame->function->variables[off - frame->variables_off].name;
220 scope = frame->scope;
222 else
224 name = frame->function->params[off - frame->arguments_off];
225 scope = frame->base_scope;
228 while (1)
230 if (scope->jsobj && SUCCEEDED(hres = jsdisp_get_id(scope->jsobj, name, 0, &id)))
231 break;
232 if (scope == frame->base_scope)
234 r->type = EXPRVAL_INVALID;
235 r->u.hres = hres;
236 return FALSE;
238 scope = scope->next;
241 *stack_top_ref(ctx, n+1) = jsval_obj(jsdisp_addref(scope->jsobj));
242 *stack_top_ref(ctx, n) = jsval_number(id);
243 r->type = EXPRVAL_IDREF;
244 r->u.idref.disp = scope->obj;
245 r->u.idref.id = id;
246 return TRUE;
249 r->type = EXPRVAL_STACK_REF;
250 r->u.off = off;
251 return TRUE;
253 case JSV_OBJECT:
254 r->type = EXPRVAL_IDREF;
255 r->u.idref.disp = get_object(v);
256 assert(is_number(stack_topn(ctx, n)));
257 r->u.idref.id = get_number(stack_topn(ctx, n));
258 return TRUE;
259 case JSV_UNDEFINED:
260 r->type = EXPRVAL_INVALID;
261 assert(is_number(stack_topn(ctx, n)));
262 r->u.hres = get_number(stack_topn(ctx, n));
263 return FALSE;
264 case JSV_NULL:
265 r->type = EXPRVAL_JSVAL;
266 r->u.val = stack_topn(ctx, n);
267 return TRUE;
268 default:
269 assert(0);
270 return FALSE;
274 static inline BOOL stack_pop_exprval(script_ctx_t *ctx, exprval_t *r)
276 BOOL ret = stack_topn_exprval(ctx, 0, r);
277 ctx->stack_top -= 2;
278 return ret;
281 static HRESULT exprval_propput(script_ctx_t *ctx, exprval_t *ref, jsval_t v)
283 switch(ref->type) {
284 case EXPRVAL_STACK_REF: {
285 jsval_t *r = ctx->stack + ref->u.off;
286 jsval_release(*r);
287 return jsval_copy(v, r);
289 case EXPRVAL_IDREF:
290 return disp_propput(ctx, ref->u.idref.disp, ref->u.idref.id, v);
291 case EXPRVAL_JSVAL:
292 WARN("ignoring an attempt to set value reference\n");
293 return S_OK;
294 default:
295 assert(0);
296 return E_FAIL;
300 static HRESULT exprval_propget(script_ctx_t *ctx, exprval_t *ref, jsval_t *r)
302 switch(ref->type) {
303 case EXPRVAL_STACK_REF:
304 return jsval_copy(ctx->stack[ref->u.off], r);
305 case EXPRVAL_IDREF:
306 return disp_propget(ctx, ref->u.idref.disp, ref->u.idref.id, r);
307 case EXPRVAL_JSVAL:
308 return jsval_copy(ref->u.val, r);
309 default:
310 assert(0);
311 return E_FAIL;
315 static HRESULT exprval_call(script_ctx_t *ctx, exprval_t *ref, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
317 switch(ref->type) {
318 case EXPRVAL_STACK_REF: {
319 jsval_t v = ctx->stack[ref->u.off];
321 if(!is_object_instance(v)) {
322 FIXME("invoke %s\n", debugstr_jsval(v));
323 return E_FAIL;
326 return disp_call_value(ctx, get_object(v), NULL, flags, argc, argv, r);
328 case EXPRVAL_IDREF:
329 return disp_call(ctx, ref->u.idref.disp, ref->u.idref.id, flags, argc, argv, r);
330 case EXPRVAL_JSVAL: {
331 IDispatch *obj;
332 HRESULT hres;
334 hres = to_object(ctx, ref->u.val, &obj);
335 if(SUCCEEDED(hres)) {
336 hres = disp_call_value(ctx, obj, NULL, flags, argc, argv, r);
337 IDispatch_Release(obj);
339 return hres;
341 default:
342 assert(0);
343 return E_FAIL;
347 /* ECMA-262 3rd Edition 8.7.1 */
348 /* Steals input reference. */
349 static HRESULT exprval_to_value(script_ctx_t *ctx, exprval_t *ref, jsval_t *r)
351 HRESULT hres;
353 if(ref->type == EXPRVAL_JSVAL) {
354 *r = ref->u.val;
355 return S_OK;
358 hres = exprval_propget(ctx, ref, r);
360 if(ref->type == EXPRVAL_IDREF)
361 IDispatch_Release(ref->u.idref.disp);
362 return hres;
365 static void exprval_release(exprval_t *val)
367 switch(val->type) {
368 case EXPRVAL_JSVAL:
369 jsval_release(val->u.val);
370 return;
371 case EXPRVAL_IDREF:
372 if(val->u.idref.disp)
373 IDispatch_Release(val->u.idref.disp);
374 return;
375 case EXPRVAL_STACK_REF:
376 case EXPRVAL_INVALID:
377 return;
381 static inline void exprval_set_exception(exprval_t *val, HRESULT hres)
383 val->type = EXPRVAL_INVALID;
384 val->u.hres = hres;
387 static inline void exprval_set_disp_ref(exprval_t *ref, IDispatch *obj, DISPID id)
389 ref->type = EXPRVAL_IDREF;
390 IDispatch_AddRef(ref->u.idref.disp = obj);
391 ref->u.idref.id = id;
394 static inline jsval_t steal_ret(call_frame_t *frame)
396 jsval_t r = frame->ret;
397 frame->ret = jsval_undefined();
398 return r;
401 static inline void clear_acc(script_ctx_t *ctx)
403 jsval_release(ctx->acc);
404 ctx->acc = jsval_undefined();
407 static HRESULT scope_push(scope_chain_t *scope, jsdisp_t *jsobj, IDispatch *obj, scope_chain_t **ret)
409 scope_chain_t *new_scope;
411 new_scope = heap_alloc(sizeof(scope_chain_t));
412 if(!new_scope)
413 return E_OUTOFMEMORY;
415 new_scope->ref = 1;
417 if (obj)
418 IDispatch_AddRef(obj);
419 new_scope->jsobj = jsobj;
420 new_scope->obj = obj;
421 new_scope->frame = NULL;
422 new_scope->next = scope ? scope_addref(scope) : NULL;
423 new_scope->scope_index = 0;
425 *ret = new_scope;
426 return S_OK;
429 static void scope_pop(scope_chain_t **scope)
431 scope_chain_t *tmp;
433 tmp = *scope;
434 *scope = tmp->next;
435 scope_release(tmp);
438 void scope_release(scope_chain_t *scope)
440 if(--scope->ref)
441 return;
443 if(scope->next)
444 scope_release(scope->next);
446 if (scope->obj)
447 IDispatch_Release(scope->obj);
448 heap_free(scope);
451 static HRESULT disp_get_id(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name, BSTR name_bstr, DWORD flags, DISPID *id)
453 IDispatchEx *dispex;
454 jsdisp_t *jsdisp;
455 BSTR bstr;
456 HRESULT hres;
458 jsdisp = iface_to_jsdisp(disp);
459 if(jsdisp) {
460 hres = jsdisp_get_id(jsdisp, name, flags, id);
461 jsdisp_release(jsdisp);
462 return hres;
465 if(name_bstr) {
466 bstr = name_bstr;
467 }else {
468 bstr = SysAllocString(name);
469 if(!bstr)
470 return E_OUTOFMEMORY;
473 *id = 0;
474 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
475 if(SUCCEEDED(hres)) {
476 hres = IDispatchEx_GetDispID(dispex, bstr, make_grfdex(ctx, flags|fdexNameCaseSensitive), id);
477 IDispatchEx_Release(dispex);
478 }else {
479 TRACE("using IDispatch\n");
480 hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, id);
483 if(name_bstr != bstr)
484 SysFreeString(bstr);
485 return hres;
488 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, BOOL *ret)
490 IObjectIdentity *identity;
491 IUnknown *unk1, *unk2;
492 HRESULT hres;
494 if(disp1 == disp2) {
495 *ret = TRUE;
496 return S_OK;
499 if(!disp1 || !disp2) {
500 *ret = FALSE;
501 return S_OK;
504 hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
505 if(FAILED(hres))
506 return hres;
508 hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
509 if(FAILED(hres)) {
510 IUnknown_Release(unk1);
511 return hres;
514 if(unk1 == unk2) {
515 *ret = TRUE;
516 }else {
517 hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
518 if(SUCCEEDED(hres)) {
519 hres = IObjectIdentity_IsEqualObject(identity, unk2);
520 IObjectIdentity_Release(identity);
521 *ret = hres == S_OK;
522 }else {
523 *ret = FALSE;
527 IUnknown_Release(unk1);
528 IUnknown_Release(unk2);
529 return S_OK;
532 /* ECMA-262 3rd Edition 11.9.6 */
533 HRESULT jsval_strict_equal(jsval_t lval, jsval_t rval, BOOL *ret)
535 jsval_type_t type = jsval_type(lval);
537 TRACE("\n");
539 if(type != jsval_type(rval)) {
540 *ret = FALSE;
541 return S_OK;
544 switch(type) {
545 case JSV_UNDEFINED:
546 case JSV_NULL:
547 *ret = TRUE;
548 break;
549 case JSV_OBJECT:
550 return disp_cmp(get_object(lval), get_object(rval), ret);
551 case JSV_STRING:
552 *ret = jsstr_eq(get_string(lval), get_string(rval));
553 break;
554 case JSV_NUMBER:
555 *ret = get_number(lval) == get_number(rval);
556 break;
557 case JSV_BOOL:
558 *ret = !get_bool(lval) == !get_bool(rval);
559 break;
560 case JSV_VARIANT:
561 WARN("VARIANT type, returning false\n");
562 *ret = FALSE;
563 return S_OK;
566 return S_OK;
569 static HRESULT detach_scope(script_ctx_t *ctx, call_frame_t *frame, scope_chain_t *scope)
571 function_code_t *func = frame->function;
572 unsigned int i, index;
573 HRESULT hres;
575 if (!scope->frame)
576 return S_OK;
578 assert(scope->frame == frame);
579 scope->frame = NULL;
581 if (!scope->jsobj)
583 assert(!scope->obj);
585 if (FAILED(hres = create_object(ctx, NULL, &scope->jsobj)))
586 return hres;
587 scope->obj = to_disp(scope->jsobj);
590 if (scope == frame->base_scope && func->name && func->local_ref == INVALID_LOCAL_REF &&
591 ctx->version >= SCRIPTLANGUAGEVERSION_ES5)
592 jsdisp_propput_name(scope->jsobj, func->name, jsval_obj(jsdisp_addref(frame->function_instance)));
594 index = scope->scope_index;
595 for(i = 0; i < frame->function->local_scopes[index].locals_cnt; i++)
597 WCHAR *name = frame->function->local_scopes[index].locals[i].name;
598 int ref = frame->function->local_scopes[index].locals[i].ref;
600 if (FAILED(hres = jsdisp_propput_name(scope->jsobj, name, ctx->stack[local_off(frame, ref)])))
601 return hres;
602 if (frame->function->variables[ref].func_id != -1 && scope != frame->base_scope
603 && FAILED(hres = jsdisp_propput_name(frame->variable_obj, name, ctx->stack[local_off(frame, ref)])))
604 return hres;
606 return S_OK;
609 static HRESULT detach_scope_chain(script_ctx_t *ctx, call_frame_t *frame, scope_chain_t *scope)
611 HRESULT hres;
613 if (scope != frame->base_scope && FAILED(hres = detach_scope_chain(ctx, frame, scope->next)))
614 return hres;
615 return detach_scope(ctx, frame, scope);
619 * Transfers local variables from stack to variable object.
620 * It's slow, so we want to avoid it as much as possible.
622 static HRESULT detach_variable_object(script_ctx_t *ctx, call_frame_t *frame, BOOL from_release)
624 HRESULT hres;
626 if(!frame->base_scope || !frame->base_scope->frame)
627 return S_OK;
629 TRACE("detaching %p\n", frame);
631 assert(frame == frame->base_scope->frame);
632 assert(frame->variable_obj == frame->base_scope->jsobj);
634 if(!from_release && !frame->arguments_obj) {
635 hres = setup_arguments_object(ctx, frame);
636 if(FAILED(hres))
637 return hres;
640 TRACE("detaching scope chain %p, frame %p.\n", ctx->call_ctx->scope, frame);
641 return detach_scope_chain(ctx, frame, ctx->call_ctx->scope);
644 static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
646 named_item_t *item;
647 DISPID id;
648 HRESULT hres;
650 LIST_FOR_EACH_ENTRY(item, &ctx->named_items, named_item_t, entry) {
651 if(item->flags & SCRIPTITEM_GLOBALMEMBERS) {
652 hres = disp_get_id(ctx, item->disp, identifier, identifier, 0, &id);
653 if(SUCCEEDED(hres)) {
654 if(ret)
655 exprval_set_disp_ref(ret, item->disp, id);
656 return TRUE;
661 return FALSE;
664 IDispatch *lookup_global_host(script_ctx_t *ctx)
666 IDispatch *disp = NULL;
667 named_item_t *item;
669 LIST_FOR_EACH_ENTRY(item, &ctx->named_items, named_item_t, entry) {
670 if(!(item->flags & SCRIPTITEM_GLOBALMEMBERS)) continue;
671 disp = item->disp;
672 break;
674 if(!disp) disp = to_disp(ctx->global);
676 return disp;
679 static int __cdecl local_ref_cmp(const void *key, const void *ref)
681 return wcscmp((const WCHAR*)key, ((const local_ref_t*)ref)->name);
684 local_ref_t *lookup_local(const function_code_t *function, const WCHAR *identifier, unsigned int scope)
686 return bsearch(identifier, function->local_scopes[scope].locals, function->local_scopes[scope].locals_cnt,
687 sizeof(*function->local_scopes[scope].locals), local_ref_cmp);
690 /* ECMA-262 3rd Edition 10.1.4 */
691 static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
693 scope_chain_t *scope;
694 named_item_t *item;
695 DISPID id = 0;
696 HRESULT hres;
698 TRACE("%s\n", debugstr_w(identifier));
700 if(ctx->call_ctx) {
701 for(scope = ctx->call_ctx->scope; scope; scope = scope->next) {
702 if(scope->frame) {
703 function_code_t *func = scope->frame->function;
704 local_ref_t *ref = lookup_local(func, identifier, scope->scope_index);
706 if(ref) {
707 ret->type = EXPRVAL_STACK_REF;
708 ret->u.off = local_off(scope->frame, ref->ref);
709 TRACE("returning ref %d for %d\n", ret->u.off, ref->ref);
710 return S_OK;
713 if(!wcscmp(identifier, L"arguments")) {
714 hres = detach_variable_object(ctx, scope->frame, FALSE);
715 if(FAILED(hres))
716 return hres;
719 /* ECMA-262 5.1 Edition 13 */
720 if(func->name && ctx->version >= SCRIPTLANGUAGEVERSION_ES5 &&
721 func->local_ref == INVALID_LOCAL_REF && !wcscmp(identifier, func->name)) {
722 TRACE("returning a function from scope chain\n");
723 ret->type = EXPRVAL_JSVAL;
724 ret->u.val = jsval_obj(jsdisp_addref(scope->frame->function_instance));
725 return S_OK;
729 if (!scope->jsobj && !scope->obj)
730 continue;
732 if(scope->jsobj)
733 hres = jsdisp_get_id(scope->jsobj, identifier, fdexNameImplicit, &id);
734 else
735 hres = disp_get_id(ctx, scope->obj, identifier, identifier, fdexNameImplicit, &id);
736 if(SUCCEEDED(hres)) {
737 exprval_set_disp_ref(ret, scope->obj, id);
738 return S_OK;
742 item = ctx->call_ctx->bytecode->named_item;
743 if(item) {
744 hres = jsdisp_get_id(item->script_obj, identifier, 0, &id);
745 if(SUCCEEDED(hres)) {
746 exprval_set_disp_ref(ret, to_disp(item->script_obj), id);
747 return S_OK;
749 if(!(item->flags & SCRIPTITEM_CODEONLY)) {
750 hres = disp_get_id(ctx, item->disp, identifier, identifier, 0, &id);
751 if(SUCCEEDED(hres)) {
752 exprval_set_disp_ref(ret, item->disp, id);
753 return S_OK;
759 hres = jsdisp_get_id(ctx->global, identifier, 0, &id);
760 if(SUCCEEDED(hres)) {
761 exprval_set_disp_ref(ret, to_disp(ctx->global), id);
762 return S_OK;
765 item = lookup_named_item(ctx, identifier, SCRIPTITEM_ISVISIBLE);
766 if(item) {
767 IDispatch_AddRef(item->disp);
768 ret->type = EXPRVAL_JSVAL;
769 ret->u.val = jsval_disp(item->disp);
770 return S_OK;
773 if(lookup_global_members(ctx, identifier, ret))
774 return S_OK;
776 exprval_set_exception(ret, JS_E_UNDEFINED_VARIABLE);
777 return S_OK;
780 static inline BSTR get_op_bstr(script_ctx_t *ctx, int i)
782 call_frame_t *frame = ctx->call_ctx;
783 return frame->bytecode->instrs[frame->ip].u.arg[i].bstr;
786 static inline unsigned get_op_uint(script_ctx_t *ctx, int i)
788 call_frame_t *frame = ctx->call_ctx;
789 return frame->bytecode->instrs[frame->ip].u.arg[i].uint;
792 static inline unsigned get_op_int(script_ctx_t *ctx, int i)
794 call_frame_t *frame = ctx->call_ctx;
795 return frame->bytecode->instrs[frame->ip].u.arg[i].lng;
798 static inline jsstr_t *get_op_str(script_ctx_t *ctx, int i)
800 call_frame_t *frame = ctx->call_ctx;
801 return frame->bytecode->instrs[frame->ip].u.arg[i].str;
804 static inline double get_op_double(script_ctx_t *ctx)
806 call_frame_t *frame = ctx->call_ctx;
807 return frame->bytecode->instrs[frame->ip].u.dbl;
810 static inline void jmp_next(script_ctx_t *ctx)
812 ctx->call_ctx->ip++;
815 static inline void jmp_abs(script_ctx_t *ctx, unsigned dst)
817 ctx->call_ctx->ip = dst;
820 /* ECMA-262 3rd Edition 12.6.4 */
821 static HRESULT interp_forin(script_ctx_t *ctx)
823 const HRESULT arg = get_op_uint(ctx, 0);
824 IDispatch *obj = NULL;
825 IDispatchEx *dispex;
826 exprval_t prop_ref;
827 DISPID id;
828 BSTR name = NULL;
829 HRESULT hres;
831 TRACE("\n");
833 assert(is_number(stack_top(ctx)));
834 id = get_number(stack_top(ctx));
836 if(!stack_topn_exprval(ctx, 1, &prop_ref)) {
837 FIXME("invalid ref: %08lx\n", prop_ref.u.hres);
838 return E_FAIL;
841 if(is_object_instance(stack_topn(ctx, 3)))
842 obj = get_object(stack_topn(ctx, 3));
844 if(obj) {
845 hres = IDispatch_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
846 if(SUCCEEDED(hres)) {
847 hres = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, id, &id);
848 if(hres == S_OK)
849 hres = IDispatchEx_GetMemberName(dispex, id, &name);
850 IDispatchEx_Release(dispex);
851 if(FAILED(hres))
852 return hres;
853 }else {
854 TRACE("No IDispatchEx\n");
858 if(name) {
859 jsstr_t *str;
861 str = jsstr_alloc_len(name, SysStringLen(name));
862 SysFreeString(name);
863 if(!str)
864 return E_OUTOFMEMORY;
866 stack_pop(ctx);
867 stack_push(ctx, jsval_number(id)); /* safe, just after pop() */
869 hres = exprval_propput(ctx, &prop_ref, jsval_string(str));
870 jsstr_release(str);
871 if(FAILED(hres))
872 return hres;
874 jmp_next(ctx);
875 }else {
876 stack_popn(ctx, 4);
877 jmp_abs(ctx, arg);
879 return S_OK;
882 static HRESULT scope_init_locals(script_ctx_t *ctx)
884 call_frame_t *frame = ctx->call_ctx;
885 unsigned int i, off, index;
886 scope_chain_t *scope;
887 BOOL detached_vars;
888 HRESULT hres;
890 scope = frame->scope;
891 index = scope->scope_index;
892 detached_vars = !(frame->base_scope && frame->base_scope->frame);
894 if (!detached_vars)
896 assert(frame->base_scope->frame == frame);
897 frame->scope->frame = ctx->call_ctx;
899 else if (!scope->jsobj)
901 assert(!scope->obj);
902 if (FAILED(hres = create_object(ctx, NULL, &scope->jsobj)))
903 return hres;
904 scope->obj = to_disp(scope->jsobj);
907 for(i = 0; i < frame->function->local_scopes[index].locals_cnt; i++)
909 WCHAR *name = frame->function->local_scopes[index].locals[i].name;
910 int ref = frame->function->local_scopes[index].locals[i].ref;
911 jsdisp_t *func_obj;
912 jsval_t val;
914 if (frame->function->variables[ref].func_id != -1)
916 TRACE("function %s %d\n", debugstr_w(name), i);
918 if (FAILED(hres = create_source_function(ctx, frame->bytecode, frame->function->funcs
919 + frame->function->variables[ref].func_id, ctx->call_ctx->scope, &func_obj)))
920 return hres;
921 val = jsval_obj(func_obj);
922 if (detached_vars && FAILED(hres = jsdisp_propput_name(frame->variable_obj, name, jsval_obj(func_obj))))
923 return hres;
925 else
927 val = jsval_undefined();
930 if (detached_vars)
932 if (FAILED(hres = jsdisp_propput_name(scope->jsobj, name, val)))
933 return hres;
935 else
937 off = local_off(frame, ref);
938 jsval_release(ctx->stack[off]);
939 ctx->stack[off] = val;
942 return S_OK;
945 /* ECMA-262 3rd Edition 12.10 */
946 static HRESULT interp_push_with_scope(script_ctx_t *ctx)
948 IDispatch *disp;
949 jsval_t v;
950 HRESULT hres;
952 TRACE("\n");
954 v = stack_pop(ctx);
955 hres = to_object(ctx, v, &disp);
956 jsval_release(v);
957 if(FAILED(hres))
958 return hres;
960 hres = scope_push(ctx->call_ctx->scope, to_jsdisp(disp), disp, &ctx->call_ctx->scope);
961 IDispatch_Release(disp);
962 return hres;
965 /* ECMA-262 10th Edition 13.3.1 */
966 static HRESULT interp_push_block_scope(script_ctx_t *ctx)
968 unsigned int scope_index = get_op_uint(ctx, 0);
969 call_frame_t *frame = ctx->call_ctx;
970 HRESULT hres;
972 TRACE("scope_index %u.\n", scope_index);
974 hres = scope_push(ctx->call_ctx->scope, NULL, NULL, &frame->scope);
976 if (FAILED(hres) || !scope_index)
977 return hres;
979 frame->scope->scope_index = scope_index;
981 return scope_init_locals(ctx);
984 /* ECMA-262 3rd Edition 12.10 */
985 static HRESULT interp_pop_scope(script_ctx_t *ctx)
987 TRACE("\n");
989 if(ctx->call_ctx->scope->ref > 1) {
990 HRESULT hres = detach_variable_object(ctx, ctx->call_ctx, FALSE);
991 if(FAILED(hres))
992 ERR("Failed to detach variable object: %08lx\n", hres);
995 scope_pop(&ctx->call_ctx->scope);
996 return S_OK;
999 /* ECMA-262 3rd Edition 12.13 */
1000 static HRESULT interp_case(script_ctx_t *ctx)
1002 const unsigned arg = get_op_uint(ctx, 0);
1003 jsval_t v;
1004 BOOL b;
1005 HRESULT hres;
1007 TRACE("\n");
1009 v = stack_pop(ctx);
1010 hres = jsval_strict_equal(stack_top(ctx), v, &b);
1011 jsval_release(v);
1012 if(FAILED(hres))
1013 return hres;
1015 if(b) {
1016 stack_popn(ctx, 1);
1017 jmp_abs(ctx, arg);
1018 }else {
1019 jmp_next(ctx);
1021 return S_OK;
1024 static void set_error_value(script_ctx_t *ctx, jsval_t value)
1026 jsexcept_t *ei = ctx->ei;
1027 jsdisp_t *obj;
1029 reset_ei(ei);
1030 ei->error = JS_E_EXCEPTION_THROWN;
1031 ei->valid_value = TRUE;
1032 ei->value = value;
1034 if(is_object_instance(value) && (obj = to_jsdisp(get_object(value)))) {
1035 UINT32 number;
1036 jsstr_t *str;
1037 jsval_t v;
1038 HRESULT hres;
1040 /* FIXME: We should check if object is an error instance */
1042 hres = jsdisp_propget_name(obj, L"number", &v);
1043 if(SUCCEEDED(hres)) {
1044 hres = to_uint32(ctx, v, &number);
1045 if(SUCCEEDED(hres))
1046 ei->error = FAILED(number) ? number : E_FAIL;
1047 jsval_release(v);
1050 hres = jsdisp_propget_name(obj, L"description", &v);
1051 if(SUCCEEDED(hres)) {
1052 hres = to_string(ctx, v, &str);
1053 if(SUCCEEDED(hres))
1054 ei->message = str;
1055 jsval_release(v);
1060 /* ECMA-262 3rd Edition 12.13 */
1061 static HRESULT interp_throw(script_ctx_t *ctx)
1063 TRACE("\n");
1065 set_error_value(ctx, stack_pop(ctx));
1066 return DISP_E_EXCEPTION;
1069 static HRESULT interp_throw_ref(script_ctx_t *ctx)
1071 const HRESULT arg = get_op_uint(ctx, 0);
1073 TRACE("%08lx\n", arg);
1075 return arg;
1078 static HRESULT interp_throw_type(script_ctx_t *ctx)
1080 const HRESULT hres = get_op_uint(ctx, 0);
1081 jsstr_t *str = get_op_str(ctx, 1);
1082 const WCHAR *ptr;
1084 TRACE("%08lx %s\n", hres, debugstr_jsstr(str));
1086 ptr = jsstr_flatten(str);
1087 return ptr ? throw_error(ctx, hres, ptr) : E_OUTOFMEMORY;
1090 /* ECMA-262 3rd Edition 12.14 */
1091 static HRESULT interp_push_except(script_ctx_t *ctx)
1093 const unsigned catch_off = get_op_uint(ctx, 0);
1094 const unsigned finally_off = get_op_uint(ctx, 1);
1095 call_frame_t *frame = ctx->call_ctx;
1096 except_frame_t *except;
1098 TRACE("\n");
1100 except = heap_alloc(sizeof(*except));
1101 if(!except)
1102 return E_OUTOFMEMORY;
1104 except->stack_top = ctx->stack_top;
1105 except->scope = frame->scope;
1106 except->catch_off = catch_off;
1107 except->finally_off = finally_off;
1108 except->next = frame->except_frame;
1109 frame->except_frame = except;
1110 return S_OK;
1113 /* ECMA-262 3rd Edition 12.14 */
1114 static HRESULT interp_pop_except(script_ctx_t *ctx)
1116 const unsigned ret_off = get_op_uint(ctx, 0);
1117 call_frame_t *frame = ctx->call_ctx;
1118 except_frame_t *except;
1119 unsigned finally_off;
1121 TRACE("%u\n", ret_off);
1123 except = frame->except_frame;
1124 assert(except != NULL);
1126 finally_off = except->finally_off;
1127 frame->except_frame = except->next;
1128 heap_free(except);
1130 if(finally_off) {
1131 HRESULT hres;
1133 hres = stack_push(ctx, jsval_number(ret_off));
1134 if(FAILED(hres))
1135 return hres;
1136 hres = stack_push(ctx, jsval_bool(TRUE));
1137 if(FAILED(hres))
1138 return hres;
1139 frame->ip = finally_off;
1140 }else {
1141 frame->ip = ret_off;
1144 return S_OK;
1147 /* ECMA-262 3rd Edition 12.14 */
1148 static HRESULT interp_end_finally(script_ctx_t *ctx)
1150 call_frame_t *frame = ctx->call_ctx;
1151 jsval_t v;
1153 TRACE("\n");
1155 v = stack_pop(ctx);
1156 assert(is_bool(v));
1158 if(!get_bool(v)) {
1159 TRACE("passing exception\n");
1161 set_error_value(ctx, stack_pop(ctx));
1162 return DISP_E_EXCEPTION;
1165 v = stack_pop(ctx);
1166 assert(is_number(v));
1167 frame->ip = get_number(v);
1168 return S_OK;
1171 static HRESULT interp_enter_catch(script_ctx_t *ctx)
1173 const BSTR ident = get_op_bstr(ctx, 0);
1174 jsdisp_t *scope_obj;
1175 jsval_t v;
1176 HRESULT hres;
1178 hres = create_dispex(ctx, NULL, NULL, &scope_obj);
1179 if(FAILED(hres))
1180 return hres;
1182 v = stack_pop(ctx);
1183 hres = jsdisp_propput_name(scope_obj, ident, v);
1184 jsval_release(v);
1185 if(SUCCEEDED(hres))
1186 hres = scope_push(ctx->call_ctx->scope, scope_obj, to_disp(scope_obj), &ctx->call_ctx->scope);
1187 jsdisp_release(scope_obj);
1188 return hres;
1191 /* ECMA-262 3rd Edition 13 */
1192 static HRESULT interp_func(script_ctx_t *ctx)
1194 unsigned func_idx = get_op_uint(ctx, 0);
1195 call_frame_t *frame = ctx->call_ctx;
1196 jsdisp_t *dispex;
1197 HRESULT hres;
1199 TRACE("%d\n", func_idx);
1201 hres = create_source_function(ctx, frame->bytecode, frame->function->funcs+func_idx,
1202 frame->scope, &dispex);
1203 if(FAILED(hres))
1204 return hres;
1206 return stack_push(ctx, jsval_obj(dispex));
1209 /* ECMA-262 3rd Edition 11.2.1 */
1210 static HRESULT interp_array(script_ctx_t *ctx)
1212 jsstr_t *name_str;
1213 const WCHAR *name;
1214 jsval_t v, namev;
1215 IDispatch *obj;
1216 DISPID id;
1217 HRESULT hres;
1219 TRACE("\n");
1221 namev = stack_pop(ctx);
1223 hres = stack_pop_object(ctx, &obj);
1224 if(FAILED(hres)) {
1225 jsval_release(namev);
1226 return hres;
1229 hres = to_flat_string(ctx, namev, &name_str, &name);
1230 jsval_release(namev);
1231 if(FAILED(hres)) {
1232 IDispatch_Release(obj);
1233 return hres;
1236 hres = disp_get_id(ctx, obj, name, NULL, 0, &id);
1237 jsstr_release(name_str);
1238 if(SUCCEEDED(hres)) {
1239 hres = disp_propget(ctx, obj, id, &v);
1240 }else if(hres == DISP_E_UNKNOWNNAME) {
1241 v = jsval_undefined();
1242 hres = S_OK;
1244 IDispatch_Release(obj);
1245 if(FAILED(hres))
1246 return hres;
1248 return stack_push(ctx, v);
1251 /* ECMA-262 3rd Edition 11.2.1 */
1252 static HRESULT interp_member(script_ctx_t *ctx)
1254 const BSTR arg = get_op_bstr(ctx, 0);
1255 IDispatch *obj;
1256 jsval_t v;
1257 DISPID id;
1258 HRESULT hres;
1260 TRACE("\n");
1262 hres = stack_pop_object(ctx, &obj);
1263 if(FAILED(hres))
1264 return hres;
1266 hres = disp_get_id(ctx, obj, arg, arg, 0, &id);
1267 if(SUCCEEDED(hres)) {
1268 hres = disp_propget(ctx, obj, id, &v);
1269 }else if(hres == DISP_E_UNKNOWNNAME) {
1270 v = jsval_undefined();
1271 hres = S_OK;
1273 IDispatch_Release(obj);
1274 if(FAILED(hres))
1275 return hres;
1277 return stack_push(ctx, v);
1280 /* ECMA-262 3rd Edition 11.2.1 */
1281 static HRESULT interp_memberid(script_ctx_t *ctx)
1283 const unsigned arg = get_op_uint(ctx, 0);
1284 jsval_t objv, namev;
1285 const WCHAR *name;
1286 jsstr_t *name_str;
1287 IDispatch *obj;
1288 exprval_t ref;
1289 DISPID id;
1290 HRESULT hres;
1292 TRACE("%x\n", arg);
1294 namev = stack_pop(ctx);
1295 objv = stack_pop(ctx);
1297 hres = to_object(ctx, objv, &obj);
1298 jsval_release(objv);
1299 if(SUCCEEDED(hres)) {
1300 hres = to_flat_string(ctx, namev, &name_str, &name);
1301 if(FAILED(hres))
1302 IDispatch_Release(obj);
1304 jsval_release(namev);
1305 if(FAILED(hres))
1306 return hres;
1308 hres = disp_get_id(ctx, obj, name, NULL, arg, &id);
1309 jsstr_release(name_str);
1310 if(SUCCEEDED(hres)) {
1311 ref.type = EXPRVAL_IDREF;
1312 ref.u.idref.disp = obj;
1313 ref.u.idref.id = id;
1314 }else {
1315 IDispatch_Release(obj);
1316 if(hres == DISP_E_UNKNOWNNAME && !(arg & fdexNameEnsure)) {
1317 exprval_set_exception(&ref, JS_E_INVALID_PROPERTY);
1318 hres = S_OK;
1319 }else {
1320 ERR("failed %08lx\n", hres);
1321 return hres;
1325 return stack_push_exprval(ctx, &ref);
1328 /* ECMA-262 3rd Edition 11.2.1 */
1329 static HRESULT interp_refval(script_ctx_t *ctx)
1331 exprval_t ref;
1332 jsval_t v;
1333 HRESULT hres;
1335 TRACE("\n");
1337 if(!stack_topn_exprval(ctx, 0, &ref))
1338 return JS_E_ILLEGAL_ASSIGN;
1340 hres = exprval_propget(ctx, &ref, &v);
1341 if(FAILED(hres))
1342 return hres;
1344 return stack_push(ctx, v);
1347 /* ECMA-262 3rd Edition 11.2.2 */
1348 static HRESULT interp_new(script_ctx_t *ctx)
1350 const unsigned argc = get_op_uint(ctx, 0);
1351 jsval_t constr;
1353 TRACE("%d\n", argc);
1355 constr = stack_topn(ctx, argc);
1357 /* NOTE: Should use to_object here */
1359 if(is_null(constr))
1360 return is_null_disp(constr) ? JS_E_INVALID_PROPERTY : JS_E_OBJECT_EXPECTED;
1361 if(!is_object_instance(constr))
1362 return JS_E_INVALID_ACTION;
1364 clear_acc(ctx);
1365 return disp_call_value(ctx, get_object(constr), NULL, DISPATCH_CONSTRUCT | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
1366 argc, stack_args(ctx, argc), &ctx->acc);
1369 /* ECMA-262 3rd Edition 11.2.3 */
1370 static HRESULT interp_call(script_ctx_t *ctx)
1372 const unsigned argn = get_op_uint(ctx, 0);
1373 const int do_ret = get_op_int(ctx, 1);
1374 jsval_t obj;
1376 TRACE("%d %d\n", argn, do_ret);
1378 obj = stack_topn(ctx, argn);
1379 if(!is_object_instance(obj))
1380 return JS_E_INVALID_PROPERTY;
1382 clear_acc(ctx);
1383 return disp_call_value(ctx, get_object(obj), NULL, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
1384 argn, stack_args(ctx, argn), do_ret ? &ctx->acc : NULL);
1387 /* ECMA-262 3rd Edition 11.2.3 */
1388 static HRESULT interp_call_member(script_ctx_t *ctx)
1390 const unsigned argn = get_op_uint(ctx, 0);
1391 const int do_ret = get_op_int(ctx, 1);
1392 exprval_t ref;
1394 TRACE("%d %d\n", argn, do_ret);
1396 if(!stack_topn_exprval(ctx, argn, &ref))
1397 return ref.u.hres;
1399 clear_acc(ctx);
1400 return exprval_call(ctx, &ref, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
1401 argn, stack_args(ctx, argn), do_ret ? &ctx->acc : NULL);
1404 /* ECMA-262 3rd Edition 11.1.1 */
1405 static HRESULT interp_this(script_ctx_t *ctx)
1407 IDispatch *this_obj = ctx->call_ctx->this_obj;
1409 TRACE("\n");
1411 if(!this_obj) {
1412 named_item_t *item = ctx->call_ctx->bytecode->named_item;
1414 if(item)
1415 this_obj = (item->flags & SCRIPTITEM_CODEONLY) ? to_disp(item->script_obj) : item->disp;
1416 else
1417 this_obj = lookup_global_host(ctx);
1420 IDispatch_AddRef(this_obj);
1421 return stack_push(ctx, jsval_disp(this_obj));
1424 static HRESULT interp_identifier_ref(script_ctx_t *ctx, BSTR identifier, unsigned flags)
1426 exprval_t exprval;
1427 HRESULT hres;
1429 hres = identifier_eval(ctx, identifier, &exprval);
1430 if(FAILED(hres))
1431 return hres;
1433 if(exprval.type == EXPRVAL_INVALID && (flags & fdexNameEnsure)) {
1434 jsdisp_t *script_obj = ctx->global;
1435 DISPID id;
1437 if(ctx->call_ctx->bytecode->named_item)
1438 script_obj = ctx->call_ctx->bytecode->named_item->script_obj;
1440 hres = jsdisp_get_id(script_obj, identifier, fdexNameEnsure, &id);
1441 if(FAILED(hres))
1442 return hres;
1444 exprval_set_disp_ref(&exprval, to_disp(script_obj), id);
1447 if(exprval.type == EXPRVAL_INVALID ||
1448 (exprval.type == EXPRVAL_JSVAL && ctx->version < SCRIPTLANGUAGEVERSION_ES5)) {
1449 WARN("invalid ref\n");
1450 exprval_release(&exprval);
1451 exprval_set_exception(&exprval, JS_E_OBJECT_EXPECTED);
1454 return stack_push_exprval(ctx, &exprval);
1457 static HRESULT identifier_value(script_ctx_t *ctx, BSTR identifier)
1459 exprval_t exprval;
1460 jsval_t v;
1461 HRESULT hres;
1463 hres = identifier_eval(ctx, identifier, &exprval);
1464 if(FAILED(hres))
1465 return hres;
1467 if(exprval.type == EXPRVAL_INVALID)
1468 return throw_error(ctx, exprval.u.hres, identifier);
1470 hres = exprval_to_value(ctx, &exprval, &v);
1471 if(FAILED(hres))
1472 return hres;
1474 return stack_push(ctx, v);
1477 static HRESULT interp_local_ref(script_ctx_t *ctx)
1479 const int arg = get_op_int(ctx, 0);
1480 const unsigned flags = get_op_uint(ctx, 1);
1481 call_frame_t *frame = ctx->call_ctx;
1482 exprval_t ref;
1484 TRACE("%s\n", debugstr_w(local_name(frame, arg)));
1486 if(!frame->base_scope || !frame->base_scope->frame)
1487 return interp_identifier_ref(ctx, local_name(frame, arg), flags);
1489 ref.type = EXPRVAL_STACK_REF;
1490 ref.u.off = local_off(frame, arg);
1491 return stack_push_exprval(ctx, &ref);
1494 static HRESULT interp_local(script_ctx_t *ctx)
1496 const int arg = get_op_int(ctx, 0);
1497 call_frame_t *frame = ctx->call_ctx;
1498 jsval_t copy;
1499 HRESULT hres;
1501 if(!frame->base_scope || !frame->base_scope->frame) {
1502 TRACE("%s\n", debugstr_w(local_name(frame, arg)));
1503 return identifier_value(ctx, local_name(frame, arg));
1506 hres = jsval_copy(ctx->stack[local_off(frame, arg)], &copy);
1507 if(FAILED(hres))
1508 return hres;
1510 TRACE("%s: %s\n", debugstr_w(local_name(frame, arg)), debugstr_jsval(copy));
1511 return stack_push(ctx, copy);
1514 /* ECMA-262 3rd Edition 10.1.4 */
1515 static HRESULT interp_ident(script_ctx_t *ctx)
1517 const BSTR arg = get_op_bstr(ctx, 0);
1519 TRACE("%s\n", debugstr_w(arg));
1521 return identifier_value(ctx, arg);
1524 /* ECMA-262 3rd Edition 10.1.4 */
1525 static HRESULT interp_identid(script_ctx_t *ctx)
1527 const BSTR arg = get_op_bstr(ctx, 0);
1528 const unsigned flags = get_op_uint(ctx, 1);
1530 TRACE("%s %x\n", debugstr_w(arg), flags);
1532 return interp_identifier_ref(ctx, arg, flags);
1535 /* ECMA-262 3rd Edition 7.8.1 */
1536 static HRESULT interp_null(script_ctx_t *ctx)
1538 TRACE("\n");
1540 return stack_push(ctx, jsval_null());
1543 /* ECMA-262 3rd Edition 7.8.2 */
1544 static HRESULT interp_bool(script_ctx_t *ctx)
1546 const int arg = get_op_int(ctx, 0);
1548 TRACE("%s\n", arg ? "true" : "false");
1550 return stack_push(ctx, jsval_bool(arg));
1553 /* ECMA-262 3rd Edition 7.8.3 */
1554 static HRESULT interp_int(script_ctx_t *ctx)
1556 const int arg = get_op_int(ctx, 0);
1558 TRACE("%d\n", arg);
1560 return stack_push(ctx, jsval_number(arg));
1563 /* ECMA-262 3rd Edition 7.8.3 */
1564 static HRESULT interp_double(script_ctx_t *ctx)
1566 const double arg = get_op_double(ctx);
1568 TRACE("%lf\n", arg);
1570 return stack_push(ctx, jsval_number(arg));
1573 /* ECMA-262 3rd Edition 7.8.4 */
1574 static HRESULT interp_str(script_ctx_t *ctx)
1576 jsstr_t *str = get_op_str(ctx, 0);
1578 TRACE("%s\n", debugstr_jsstr(str));
1580 return stack_push(ctx, jsval_string(jsstr_addref(str)));
1583 /* ECMA-262 3rd Edition 7.8 */
1584 static HRESULT interp_regexp(script_ctx_t *ctx)
1586 jsstr_t *source = get_op_str(ctx, 0);
1587 const unsigned flags = get_op_uint(ctx, 1);
1588 jsdisp_t *regexp;
1589 HRESULT hres;
1591 TRACE("%s %x\n", debugstr_jsstr(source), flags);
1593 hres = create_regexp(ctx, source, flags, &regexp);
1594 if(FAILED(hres))
1595 return hres;
1597 return stack_push(ctx, jsval_obj(regexp));
1600 /* ECMA-262 3rd Edition 11.1.4 */
1601 static HRESULT interp_carray(script_ctx_t *ctx)
1603 const unsigned arg = get_op_uint(ctx, 0);
1604 jsdisp_t *array;
1605 HRESULT hres;
1607 TRACE("%u\n", arg);
1609 hres = create_array(ctx, arg, &array);
1610 if(FAILED(hres))
1611 return hres;
1613 return stack_push(ctx, jsval_obj(array));
1616 static HRESULT interp_carray_set(script_ctx_t *ctx)
1618 const unsigned index = get_op_uint(ctx, 0);
1619 jsval_t value, array;
1620 HRESULT hres;
1622 value = stack_pop(ctx);
1624 TRACE("[%u] = %s\n", index, debugstr_jsval(value));
1626 array = stack_top(ctx);
1627 assert(is_object_instance(array));
1629 hres = jsdisp_propput_idx(iface_to_jsdisp(get_object(array)), index, value);
1630 jsval_release(value);
1631 return hres;
1634 /* ECMA-262 3rd Edition 11.1.5 */
1635 static HRESULT interp_new_obj(script_ctx_t *ctx)
1637 jsdisp_t *obj;
1638 HRESULT hres;
1640 TRACE("\n");
1642 hres = create_object(ctx, NULL, &obj);
1643 if(FAILED(hres))
1644 return hres;
1646 return stack_push(ctx, jsval_obj(obj));
1649 /* ECMA-262 3rd Edition 11.1.5 */
1650 static HRESULT interp_obj_prop(script_ctx_t *ctx)
1652 jsstr_t *name_arg = get_op_str(ctx, 0);
1653 unsigned type = get_op_uint(ctx, 1);
1654 const WCHAR *name;
1655 jsdisp_t *obj;
1656 jsval_t val;
1657 HRESULT hres;
1659 TRACE("%s\n", debugstr_jsstr(name_arg));
1661 val = stack_pop(ctx);
1663 /* FIXME: we should pass it as jsstr_t */
1664 name = jsstr_flatten(name_arg);
1666 assert(is_object_instance(stack_top(ctx)));
1667 obj = as_jsdisp(get_object(stack_top(ctx)));
1669 if(type == PROPERTY_DEFINITION_VALUE) {
1670 hres = jsdisp_propput_name(obj, name, val);
1671 }else {
1672 property_desc_t desc = {PROPF_ENUMERABLE | PROPF_CONFIGURABLE};
1673 jsdisp_t *func;
1675 assert(is_object_instance(val));
1676 func = iface_to_jsdisp(get_object(val));
1678 desc.mask = desc.flags;
1679 if(type == PROPERTY_DEFINITION_GETTER) {
1680 desc.explicit_getter = TRUE;
1681 desc.getter = func;
1682 }else {
1683 desc.explicit_setter = TRUE;
1684 desc.setter = func;
1687 hres = jsdisp_define_property(obj, name, &desc);
1688 jsdisp_release(func);
1691 jsval_release(val);
1692 return hres;
1695 /* ECMA-262 3rd Edition 11.11 */
1696 static HRESULT interp_cnd_nz(script_ctx_t *ctx)
1698 const unsigned arg = get_op_uint(ctx, 0);
1699 BOOL b;
1700 HRESULT hres;
1702 TRACE("\n");
1704 hres = to_boolean(stack_top(ctx), &b);
1705 if(FAILED(hres))
1706 return hres;
1708 if(b) {
1709 jmp_abs(ctx, arg);
1710 }else {
1711 stack_popn(ctx, 1);
1712 jmp_next(ctx);
1714 return S_OK;
1717 /* ECMA-262 3rd Edition 11.11 */
1718 static HRESULT interp_cnd_z(script_ctx_t *ctx)
1720 const unsigned arg = get_op_uint(ctx, 0);
1721 BOOL b;
1722 HRESULT hres;
1724 TRACE("\n");
1726 hres = to_boolean(stack_top(ctx), &b);
1727 if(FAILED(hres))
1728 return hres;
1730 if(b) {
1731 stack_popn(ctx, 1);
1732 jmp_next(ctx);
1733 }else {
1734 jmp_abs(ctx, arg);
1736 return S_OK;
1739 /* ECMA-262 3rd Edition 11.10 */
1740 static HRESULT interp_or(script_ctx_t *ctx)
1742 INT l, r;
1743 HRESULT hres;
1745 TRACE("\n");
1747 hres = stack_pop_int(ctx, &r);
1748 if(FAILED(hres))
1749 return hres;
1751 hres = stack_pop_int(ctx, &l);
1752 if(FAILED(hres))
1753 return hres;
1755 return stack_push(ctx, jsval_number(l|r));
1758 /* ECMA-262 3rd Edition 11.10 */
1759 static HRESULT interp_xor(script_ctx_t *ctx)
1761 INT l, r;
1762 HRESULT hres;
1764 TRACE("\n");
1766 hres = stack_pop_int(ctx, &r);
1767 if(FAILED(hres))
1768 return hres;
1770 hres = stack_pop_int(ctx, &l);
1771 if(FAILED(hres))
1772 return hres;
1774 return stack_push(ctx, jsval_number(l^r));
1777 /* ECMA-262 3rd Edition 11.10 */
1778 static HRESULT interp_and(script_ctx_t *ctx)
1780 INT l, r;
1781 HRESULT hres;
1783 TRACE("\n");
1785 hres = stack_pop_int(ctx, &r);
1786 if(FAILED(hres))
1787 return hres;
1789 hres = stack_pop_int(ctx, &l);
1790 if(FAILED(hres))
1791 return hres;
1793 return stack_push(ctx, jsval_number(l&r));
1796 /* ECMA-262 3rd Edition 11.8.6 */
1797 static HRESULT interp_instanceof(script_ctx_t *ctx)
1799 jsdisp_t *obj, *iter, *tmp = NULL;
1800 jsval_t prot, v;
1801 BOOL ret = FALSE;
1802 HRESULT hres;
1804 v = stack_pop(ctx);
1805 if(!is_object_instance(v)) {
1806 jsval_release(v);
1807 return JS_E_FUNCTION_EXPECTED;
1810 obj = iface_to_jsdisp(get_object(v));
1811 IDispatch_Release(get_object(v));
1812 if(!obj) {
1813 FIXME("non-jsdisp objects not supported\n");
1814 return E_FAIL;
1817 if(is_class(obj, JSCLASS_FUNCTION)) {
1818 hres = jsdisp_propget_name(obj, L"prototype", &prot);
1819 }else {
1820 hres = JS_E_FUNCTION_EXPECTED;
1822 jsdisp_release(obj);
1823 if(FAILED(hres))
1824 return hres;
1826 v = stack_pop(ctx);
1828 if(is_null_disp(v))
1829 hres = JS_E_OBJECT_EXPECTED;
1830 else if(is_object_instance(prot)) {
1831 if(is_object_instance(v))
1832 tmp = iface_to_jsdisp(get_object(v));
1833 for(iter = tmp; !ret && iter; iter = iter->prototype) {
1834 hres = disp_cmp(get_object(prot), to_disp(iter), &ret);
1835 if(FAILED(hres))
1836 break;
1839 if(tmp)
1840 jsdisp_release(tmp);
1841 }else {
1842 FIXME("prototype is not an object\n");
1843 hres = E_FAIL;
1846 jsval_release(prot);
1847 jsval_release(v);
1848 if(FAILED(hres))
1849 return hres;
1851 return stack_push(ctx, jsval_bool(ret));
1854 /* ECMA-262 3rd Edition 11.8.7 */
1855 static HRESULT interp_in(script_ctx_t *ctx)
1857 const WCHAR *str;
1858 jsstr_t *jsstr;
1859 jsval_t obj, v;
1860 DISPID id = 0;
1861 BOOL ret;
1862 HRESULT hres;
1864 TRACE("\n");
1866 obj = stack_pop(ctx);
1867 if(!is_object_instance(obj)) {
1868 jsval_release(obj);
1869 return JS_E_OBJECT_EXPECTED;
1872 v = stack_pop(ctx);
1873 hres = to_flat_string(ctx, v, &jsstr, &str);
1874 jsval_release(v);
1875 if(FAILED(hres)) {
1876 IDispatch_Release(get_object(obj));
1877 return hres;
1880 hres = disp_get_id(ctx, get_object(obj), str, NULL, 0, &id);
1881 IDispatch_Release(get_object(obj));
1882 jsstr_release(jsstr);
1883 if(SUCCEEDED(hres))
1884 ret = TRUE;
1885 else if(hres == DISP_E_UNKNOWNNAME)
1886 ret = FALSE;
1887 else
1888 return hres;
1890 return stack_push(ctx, jsval_bool(ret));
1893 /* ECMA-262 3rd Edition 11.6.1 */
1894 static HRESULT interp_add(script_ctx_t *ctx)
1896 jsval_t l, r, lval, rval, ret;
1897 HRESULT hres;
1899 rval = stack_pop(ctx);
1900 lval = stack_pop(ctx);
1902 TRACE("%s + %s\n", debugstr_jsval(lval), debugstr_jsval(rval));
1904 hres = to_primitive(ctx, lval, &l, NO_HINT);
1905 if(SUCCEEDED(hres)) {
1906 hres = to_primitive(ctx, rval, &r, NO_HINT);
1907 if(FAILED(hres))
1908 jsval_release(l);
1910 jsval_release(lval);
1911 jsval_release(rval);
1912 if(FAILED(hres))
1913 return hres;
1915 if(is_string(l) || is_string(r)) {
1916 jsstr_t *lstr, *rstr = NULL;
1918 hres = to_string(ctx, l, &lstr);
1919 if(SUCCEEDED(hres))
1920 hres = to_string(ctx, r, &rstr);
1922 if(SUCCEEDED(hres)) {
1923 jsstr_t *ret_str;
1925 ret_str = jsstr_concat(lstr, rstr);
1926 if(ret_str)
1927 ret = jsval_string(ret_str);
1928 else
1929 hres = E_OUTOFMEMORY;
1932 jsstr_release(lstr);
1933 if(rstr)
1934 jsstr_release(rstr);
1935 }else {
1936 double nl, nr;
1938 hres = to_number(ctx, l, &nl);
1939 if(SUCCEEDED(hres)) {
1940 hres = to_number(ctx, r, &nr);
1941 if(SUCCEEDED(hres))
1942 ret = jsval_number(nl+nr);
1946 jsval_release(r);
1947 jsval_release(l);
1948 if(FAILED(hres))
1949 return hres;
1951 return stack_push(ctx, ret);
1954 /* ECMA-262 3rd Edition 11.6.2 */
1955 static HRESULT interp_sub(script_ctx_t *ctx)
1957 double l, r;
1958 HRESULT hres;
1960 TRACE("\n");
1962 hres = stack_pop_number(ctx, &r);
1963 if(FAILED(hres))
1964 return hres;
1966 hres = stack_pop_number(ctx, &l);
1967 if(FAILED(hres))
1968 return hres;
1970 return stack_push(ctx, jsval_number(l-r));
1973 /* ECMA-262 3rd Edition 11.5.1 */
1974 static HRESULT interp_mul(script_ctx_t *ctx)
1976 double l, r;
1977 HRESULT hres;
1979 TRACE("\n");
1981 hres = stack_pop_number(ctx, &r);
1982 if(FAILED(hres))
1983 return hres;
1985 hres = stack_pop_number(ctx, &l);
1986 if(FAILED(hres))
1987 return hres;
1989 return stack_push(ctx, jsval_number(l*r));
1992 /* ECMA-262 3rd Edition 11.5.2 */
1993 static HRESULT interp_div(script_ctx_t *ctx)
1995 double l, r;
1996 HRESULT hres;
1998 TRACE("\n");
2000 hres = stack_pop_number(ctx, &r);
2001 if(FAILED(hres))
2002 return hres;
2004 hres = stack_pop_number(ctx, &l);
2005 if(FAILED(hres))
2006 return hres;
2008 return stack_push(ctx, jsval_number(l/r));
2011 /* ECMA-262 3rd Edition 11.5.3 */
2012 static HRESULT interp_mod(script_ctx_t *ctx)
2014 double l, r;
2015 HRESULT hres;
2017 TRACE("\n");
2019 hres = stack_pop_number(ctx, &r);
2020 if(FAILED(hres))
2021 return hres;
2023 hres = stack_pop_number(ctx, &l);
2024 if(FAILED(hres))
2025 return hres;
2027 return stack_push(ctx, jsval_number(fmod(l, r)));
2030 /* ECMA-262 3rd Edition 11.4.2 */
2031 static HRESULT interp_delete(script_ctx_t *ctx)
2033 jsval_t objv, namev;
2034 IDispatch *obj;
2035 jsstr_t *name;
2036 BOOL ret;
2037 HRESULT hres;
2039 TRACE("\n");
2041 namev = stack_pop(ctx);
2042 objv = stack_pop(ctx);
2044 hres = to_object(ctx, objv, &obj);
2045 jsval_release(objv);
2046 if(FAILED(hres)) {
2047 jsval_release(namev);
2048 return hres;
2051 hres = to_string(ctx, namev, &name);
2052 jsval_release(namev);
2053 if(FAILED(hres)) {
2054 IDispatch_Release(obj);
2055 return hres;
2058 hres = disp_delete_name(ctx, obj, name, &ret);
2059 IDispatch_Release(obj);
2060 jsstr_release(name);
2061 if(FAILED(hres))
2062 return hres;
2064 return stack_push(ctx, jsval_bool(ret));
2067 /* ECMA-262 3rd Edition 11.4.2 */
2068 static HRESULT interp_delete_ident(script_ctx_t *ctx)
2070 const BSTR arg = get_op_bstr(ctx, 0);
2071 exprval_t exprval;
2072 BOOL ret;
2073 HRESULT hres;
2075 TRACE("%s\n", debugstr_w(arg));
2077 hres = identifier_eval(ctx, arg, &exprval);
2078 if(FAILED(hres))
2079 return hres;
2081 switch(exprval.type) {
2082 case EXPRVAL_STACK_REF:
2083 ret = FALSE;
2084 break;
2085 case EXPRVAL_IDREF:
2086 hres = disp_delete(exprval.u.idref.disp, exprval.u.idref.id, &ret);
2087 IDispatch_Release(exprval.u.idref.disp);
2088 if(FAILED(hres))
2089 return hres;
2090 break;
2091 case EXPRVAL_INVALID:
2092 ret = TRUE;
2093 break;
2094 default:
2095 FIXME("Unsupported exprval\n");
2096 exprval_release(&exprval);
2097 return E_NOTIMPL;
2101 return stack_push(ctx, jsval_bool(ret));
2104 /* ECMA-262 3rd Edition 11.4.2 */
2105 static HRESULT interp_void(script_ctx_t *ctx)
2107 TRACE("\n");
2109 stack_popn(ctx, 1);
2110 return stack_push(ctx, jsval_undefined());
2113 /* ECMA-262 3rd Edition 11.4.3 */
2114 static HRESULT typeof_string(jsval_t v, const WCHAR **ret)
2116 switch(jsval_type(v)) {
2117 case JSV_UNDEFINED:
2118 *ret = L"undefined";
2119 break;
2120 case JSV_NULL:
2121 *ret = L"object";
2122 break;
2123 case JSV_OBJECT: {
2124 jsdisp_t *dispex;
2126 if((dispex = iface_to_jsdisp(get_object(v)))) {
2127 *ret = is_class(dispex, JSCLASS_FUNCTION) ? L"function" : L"object";
2128 jsdisp_release(dispex);
2129 }else {
2130 *ret = L"object";
2132 break;
2134 case JSV_STRING:
2135 *ret = L"string";
2136 break;
2137 case JSV_NUMBER:
2138 *ret = L"number";
2139 break;
2140 case JSV_BOOL:
2141 *ret = L"boolean";
2142 break;
2143 case JSV_VARIANT:
2144 FIXME("unhandled variant %s\n", debugstr_variant(get_variant(v)));
2145 return E_NOTIMPL;
2148 return S_OK;
2151 /* ECMA-262 3rd Edition 11.4.3 */
2152 static HRESULT interp_typeofid(script_ctx_t *ctx)
2154 const WCHAR *ret;
2155 exprval_t ref;
2156 jsval_t v;
2157 HRESULT hres;
2159 TRACE("\n");
2161 if(!stack_pop_exprval(ctx, &ref))
2162 return stack_push(ctx, jsval_string(jsstr_undefined()));
2164 hres = exprval_propget(ctx, &ref, &v);
2165 exprval_release(&ref);
2166 if(FAILED(hres))
2167 return stack_push_string(ctx, L"unknown");
2169 hres = typeof_string(v, &ret);
2170 jsval_release(v);
2171 if(FAILED(hres))
2172 return hres;
2174 return stack_push_string(ctx, ret);
2177 /* ECMA-262 3rd Edition 11.4.3 */
2178 static HRESULT interp_typeofident(script_ctx_t *ctx)
2180 const BSTR arg = get_op_bstr(ctx, 0);
2181 exprval_t exprval;
2182 const WCHAR *ret;
2183 jsval_t v;
2184 HRESULT hres;
2186 TRACE("%s\n", debugstr_w(arg));
2188 hres = identifier_eval(ctx, arg, &exprval);
2189 if(FAILED(hres))
2190 return hres;
2192 if(exprval.type == EXPRVAL_INVALID)
2193 return stack_push(ctx, jsval_string(jsstr_undefined()));
2195 hres = exprval_to_value(ctx, &exprval, &v);
2196 if(FAILED(hres))
2197 return hres;
2199 hres = typeof_string(v, &ret);
2200 jsval_release(v);
2201 if(FAILED(hres))
2202 return hres;
2204 return stack_push_string(ctx, ret);
2207 /* ECMA-262 3rd Edition 11.4.3 */
2208 static HRESULT interp_typeof(script_ctx_t *ctx)
2210 const WCHAR *ret;
2211 jsval_t v;
2212 HRESULT hres;
2214 TRACE("\n");
2216 v = stack_pop(ctx);
2217 hres = typeof_string(v, &ret);
2218 jsval_release(v);
2219 if(FAILED(hres))
2220 return hres;
2222 return stack_push_string(ctx, ret);
2225 /* ECMA-262 3rd Edition 11.4.7 */
2226 static HRESULT interp_minus(script_ctx_t *ctx)
2228 double n;
2229 HRESULT hres;
2231 TRACE("\n");
2233 hres = stack_pop_number(ctx, &n);
2234 if(FAILED(hres))
2235 return hres;
2237 return stack_push(ctx, jsval_number(-n));
2240 /* ECMA-262 3rd Edition 11.4.6 */
2241 static HRESULT interp_tonum(script_ctx_t *ctx)
2243 jsval_t v;
2244 double n;
2245 HRESULT hres;
2247 TRACE("\n");
2249 v = stack_pop(ctx);
2250 hres = to_number(ctx, v, &n);
2251 jsval_release(v);
2252 if(FAILED(hres))
2253 return hres;
2255 return stack_push(ctx, jsval_number(n));
2258 /* ECMA-262 3rd Edition 11.3.1 */
2259 static HRESULT interp_postinc(script_ctx_t *ctx)
2261 const int arg = get_op_int(ctx, 0);
2262 exprval_t ref;
2263 jsval_t v;
2264 HRESULT hres;
2266 TRACE("%d\n", arg);
2268 if(!stack_pop_exprval(ctx, &ref))
2269 return JS_E_OBJECT_EXPECTED;
2271 hres = exprval_propget(ctx, &ref, &v);
2272 if(SUCCEEDED(hres)) {
2273 double n;
2275 hres = to_number(ctx, v, &n);
2276 if(SUCCEEDED(hres))
2277 hres = exprval_propput(ctx, &ref, jsval_number(n+(double)arg));
2278 if(FAILED(hres))
2279 jsval_release(v);
2281 exprval_release(&ref);
2282 if(FAILED(hres))
2283 return hres;
2285 return stack_push(ctx, v);
2288 /* ECMA-262 3rd Edition 11.4.4, 11.4.5 */
2289 static HRESULT interp_preinc(script_ctx_t *ctx)
2291 const int arg = get_op_int(ctx, 0);
2292 exprval_t ref;
2293 double ret;
2294 jsval_t v;
2295 HRESULT hres;
2297 TRACE("%d\n", arg);
2299 if(!stack_pop_exprval(ctx, &ref))
2300 return JS_E_OBJECT_EXPECTED;
2302 hres = exprval_propget(ctx, &ref, &v);
2303 if(SUCCEEDED(hres)) {
2304 double n;
2306 hres = to_number(ctx, v, &n);
2307 jsval_release(v);
2308 if(SUCCEEDED(hres)) {
2309 ret = n+(double)arg;
2310 hres = exprval_propput(ctx, &ref, jsval_number(ret));
2313 exprval_release(&ref);
2314 if(FAILED(hres))
2315 return hres;
2317 return stack_push(ctx, jsval_number(ret));
2320 /* ECMA-262 3rd Edition 11.9.3 */
2321 static HRESULT equal_values(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL *ret)
2323 if(jsval_type(lval) == jsval_type(rval) || (is_number(lval) && is_number(rval)))
2324 return jsval_strict_equal(lval, rval, ret);
2326 if((is_null(lval) && is_undefined(rval)) || (is_undefined(lval) && is_null(rval))) {
2327 *ret = TRUE;
2328 return S_OK;
2331 if(is_string(lval) && is_number(rval)) {
2332 double n;
2333 HRESULT hres;
2335 hres = to_number(ctx, lval, &n);
2336 if(FAILED(hres))
2337 return hres;
2339 /* FIXME: optimize */
2340 return equal_values(ctx, jsval_number(n), rval, ret);
2343 if(is_string(rval) && is_number(lval)) {
2344 double n;
2345 HRESULT hres;
2347 hres = to_number(ctx, rval, &n);
2348 if(FAILED(hres))
2349 return hres;
2351 /* FIXME: optimize */
2352 return equal_values(ctx, lval, jsval_number(n), ret);
2355 if(is_bool(rval))
2356 return equal_values(ctx, lval, jsval_number(get_bool(rval) ? 1 : 0), ret);
2358 if(is_bool(lval))
2359 return equal_values(ctx, jsval_number(get_bool(lval) ? 1 : 0), rval, ret);
2362 if(is_object_instance(rval) && (is_string(lval) || is_number(lval))) {
2363 jsval_t prim;
2364 HRESULT hres;
2366 hres = to_primitive(ctx, rval, &prim, NO_HINT);
2367 if(FAILED(hres))
2368 return hres;
2370 hres = equal_values(ctx, lval, prim, ret);
2371 jsval_release(prim);
2372 return hres;
2376 if(is_object_instance(lval) && (is_string(rval) || is_number(rval))) {
2377 jsval_t prim;
2378 HRESULT hres;
2380 hres = to_primitive(ctx, lval, &prim, NO_HINT);
2381 if(FAILED(hres))
2382 return hres;
2384 hres = equal_values(ctx, prim, rval, ret);
2385 jsval_release(prim);
2386 return hres;
2390 *ret = FALSE;
2391 return S_OK;
2394 /* ECMA-262 3rd Edition 11.9.1 */
2395 static HRESULT interp_eq(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 = equal_values(ctx, l, r, &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.9.2 */
2416 static HRESULT interp_neq(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 = equal_values(ctx, l, r, &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.9.4 */
2437 static HRESULT interp_eq2(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 = jsval_strict_equal(r, l, &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.9.5 */
2458 static HRESULT interp_neq2(script_ctx_t *ctx)
2460 jsval_t l, r;
2461 BOOL b;
2462 HRESULT hres;
2464 TRACE("\n");
2466 r = stack_pop(ctx);
2467 l = stack_pop(ctx);
2469 hres = jsval_strict_equal(r, l, &b);
2470 jsval_release(l);
2471 jsval_release(r);
2472 if(FAILED(hres))
2473 return hres;
2475 return stack_push(ctx, jsval_bool(!b));
2478 /* ECMA-262 3rd Edition 11.8.5 */
2479 static HRESULT less_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL greater, BOOL *ret)
2481 double ln, rn;
2482 jsval_t l, r;
2483 HRESULT hres;
2485 hres = to_primitive(ctx, lval, &l, NO_HINT);
2486 if(FAILED(hres))
2487 return hres;
2489 hres = to_primitive(ctx, rval, &r, NO_HINT);
2490 if(FAILED(hres)) {
2491 jsval_release(l);
2492 return hres;
2495 if(is_string(l) && is_string(r)) {
2496 *ret = (jsstr_cmp(get_string(l), get_string(r)) < 0) ^ greater;
2497 jsstr_release(get_string(l));
2498 jsstr_release(get_string(r));
2499 return S_OK;
2502 hres = to_number(ctx, l, &ln);
2503 jsval_release(l);
2504 if(SUCCEEDED(hres))
2505 hres = to_number(ctx, r, &rn);
2506 jsval_release(r);
2507 if(FAILED(hres))
2508 return hres;
2510 *ret = !isnan(ln) && !isnan(rn) && ((ln < rn) ^ greater);
2511 return S_OK;
2514 /* ECMA-262 3rd Edition 11.8.1 */
2515 static HRESULT interp_lt(script_ctx_t *ctx)
2517 jsval_t l, r;
2518 BOOL b;
2519 HRESULT hres;
2521 r = stack_pop(ctx);
2522 l = stack_pop(ctx);
2524 TRACE("%s < %s\n", debugstr_jsval(l), debugstr_jsval(r));
2526 hres = less_eval(ctx, l, r, FALSE, &b);
2527 jsval_release(l);
2528 jsval_release(r);
2529 if(FAILED(hres))
2530 return hres;
2532 return stack_push(ctx, jsval_bool(b));
2535 /* ECMA-262 3rd Edition 11.8.1 */
2536 static HRESULT interp_lteq(script_ctx_t *ctx)
2538 jsval_t l, r;
2539 BOOL b;
2540 HRESULT hres;
2542 r = stack_pop(ctx);
2543 l = stack_pop(ctx);
2545 TRACE("%s <= %s\n", debugstr_jsval(l), debugstr_jsval(r));
2547 hres = less_eval(ctx, r, l, TRUE, &b);
2548 jsval_release(l);
2549 jsval_release(r);
2550 if(FAILED(hres))
2551 return hres;
2553 return stack_push(ctx, jsval_bool(b));
2556 /* ECMA-262 3rd Edition 11.8.2 */
2557 static HRESULT interp_gt(script_ctx_t *ctx)
2559 jsval_t l, r;
2560 BOOL b;
2561 HRESULT hres;
2563 r = stack_pop(ctx);
2564 l = stack_pop(ctx);
2566 TRACE("%s > %s\n", debugstr_jsval(l), debugstr_jsval(r));
2568 hres = less_eval(ctx, r, l, FALSE, &b);
2569 jsval_release(l);
2570 jsval_release(r);
2571 if(FAILED(hres))
2572 return hres;
2574 return stack_push(ctx, jsval_bool(b));
2577 /* ECMA-262 3rd Edition 11.8.4 */
2578 static HRESULT interp_gteq(script_ctx_t *ctx)
2580 jsval_t l, r;
2581 BOOL b;
2582 HRESULT hres;
2584 r = stack_pop(ctx);
2585 l = stack_pop(ctx);
2587 TRACE("%s >= %s\n", debugstr_jsval(l), debugstr_jsval(r));
2589 hres = less_eval(ctx, l, r, TRUE, &b);
2590 jsval_release(l);
2591 jsval_release(r);
2592 if(FAILED(hres))
2593 return hres;
2595 return stack_push(ctx, jsval_bool(b));
2598 /* ECMA-262 3rd Edition 11.4.8 */
2599 static HRESULT interp_bneg(script_ctx_t *ctx)
2601 jsval_t v;
2602 INT i;
2603 HRESULT hres;
2605 TRACE("\n");
2607 v = stack_pop(ctx);
2608 hres = to_int32(ctx, v, &i);
2609 jsval_release(v);
2610 if(FAILED(hres))
2611 return hres;
2613 return stack_push(ctx, jsval_number(~i));
2616 /* ECMA-262 3rd Edition 11.4.9 */
2617 static HRESULT interp_neg(script_ctx_t *ctx)
2619 jsval_t v;
2620 BOOL b;
2621 HRESULT hres;
2623 TRACE("\n");
2625 v = stack_pop(ctx);
2626 hres = to_boolean(v, &b);
2627 jsval_release(v);
2628 if(FAILED(hres))
2629 return hres;
2631 return stack_push(ctx, jsval_bool(!b));
2634 /* ECMA-262 3rd Edition 11.7.1 */
2635 static HRESULT interp_lshift(script_ctx_t *ctx)
2637 UINT32 r;
2638 INT l;
2639 HRESULT hres;
2641 hres = stack_pop_uint(ctx, &r);
2642 if(FAILED(hres))
2643 return hres;
2645 hres = stack_pop_int(ctx, &l);
2646 if(FAILED(hres))
2647 return hres;
2649 return stack_push(ctx, jsval_number(l << (r&0x1f)));
2652 /* ECMA-262 3rd Edition 11.7.2 */
2653 static HRESULT interp_rshift(script_ctx_t *ctx)
2655 UINT32 r;
2656 INT l;
2657 HRESULT hres;
2659 hres = stack_pop_uint(ctx, &r);
2660 if(FAILED(hres))
2661 return hres;
2663 hres = stack_pop_int(ctx, &l);
2664 if(FAILED(hres))
2665 return hres;
2667 return stack_push(ctx, jsval_number(l >> (r&0x1f)));
2670 /* ECMA-262 3rd Edition 11.7.3 */
2671 static HRESULT interp_rshift2(script_ctx_t *ctx)
2673 UINT32 r, l;
2674 HRESULT hres;
2676 hres = stack_pop_uint(ctx, &r);
2677 if(FAILED(hres))
2678 return hres;
2680 hres = stack_pop_uint(ctx, &l);
2681 if(FAILED(hres))
2682 return hres;
2684 return stack_push(ctx, jsval_number(l >> (r&0x1f)));
2687 /* ECMA-262 3rd Edition 9.8 */
2688 static HRESULT interp_to_string(script_ctx_t *ctx)
2690 jsstr_t *str;
2691 jsval_t v;
2692 HRESULT hres;
2694 v = stack_pop(ctx);
2695 TRACE("%s\n", debugstr_jsval(v));
2696 hres = to_string(ctx, v, &str);
2697 jsval_release(v);
2698 if(FAILED(hres)) {
2699 WARN("failed %08lx\n", hres);
2700 return hres;
2703 return stack_push(ctx, jsval_string(str));
2706 /* ECMA-262 3rd Edition 11.13.1 */
2707 static HRESULT interp_assign(script_ctx_t *ctx)
2709 exprval_t ref;
2710 jsval_t v;
2711 HRESULT hres;
2713 TRACE("\n");
2715 v = stack_pop(ctx);
2717 if(!stack_pop_exprval(ctx, &ref)) {
2718 jsval_release(v);
2719 return JS_E_ILLEGAL_ASSIGN;
2722 hres = exprval_propput(ctx, &ref, v);
2723 exprval_release(&ref);
2724 if(FAILED(hres)) {
2725 jsval_release(v);
2726 return hres;
2729 return stack_push(ctx, v);
2732 /* ECMA-262 3rd Edition 11.13.1 */
2733 static HRESULT interp_set_member(script_ctx_t *ctx)
2735 jsval_t objv, namev, value;
2736 const WCHAR *name;
2737 IDispatch *obj;
2738 HRESULT hres;
2740 value = stack_pop(ctx);
2741 namev = stack_pop(ctx);
2742 assert(is_string(namev));
2743 objv = stack_pop(ctx);
2745 TRACE("%s.%s = %s\n", debugstr_jsval(objv), debugstr_jsval(namev), debugstr_jsval(value));
2747 hres = to_object(ctx, objv, &obj);
2748 jsval_release(objv);
2749 if(SUCCEEDED(hres) && !(name = jsstr_flatten(get_string(namev)))) {
2750 IDispatch_Release(obj);
2751 hres = E_OUTOFMEMORY;
2753 if(SUCCEEDED(hres)) {
2754 hres = disp_propput_name(ctx, obj, name, value);
2755 IDispatch_Release(obj);
2756 jsstr_release(get_string(namev));
2758 if(FAILED(hres)) {
2759 WARN("failed %08lx\n", hres);
2760 jsval_release(value);
2761 return hres;
2764 return stack_push(ctx, value);
2767 /* JScript extension */
2768 static HRESULT interp_assign_call(script_ctx_t *ctx)
2770 const unsigned argc = get_op_uint(ctx, 0);
2771 exprval_t ref;
2772 jsval_t v;
2773 HRESULT hres;
2775 TRACE("%u\n", argc);
2777 if(!stack_topn_exprval(ctx, argc+1, &ref))
2778 return JS_E_ILLEGAL_ASSIGN;
2780 hres = exprval_call(ctx, &ref, DISPATCH_PROPERTYPUT, argc+1, stack_args(ctx, argc+1), NULL);
2781 if(FAILED(hres))
2782 return hres;
2784 v = stack_pop(ctx);
2785 stack_popn(ctx, argc+2);
2786 return stack_push(ctx, v);
2789 static HRESULT interp_undefined(script_ctx_t *ctx)
2791 TRACE("\n");
2793 return stack_push(ctx, jsval_undefined());
2796 static HRESULT interp_jmp(script_ctx_t *ctx)
2798 const unsigned arg = get_op_uint(ctx, 0);
2800 TRACE("%u\n", arg);
2802 jmp_abs(ctx, arg);
2803 return S_OK;
2806 static HRESULT interp_jmp_z(script_ctx_t *ctx)
2808 const unsigned arg = get_op_uint(ctx, 0);
2809 BOOL b;
2810 jsval_t v;
2811 HRESULT hres;
2813 TRACE("\n");
2815 v = stack_pop(ctx);
2816 hres = to_boolean(v, &b);
2817 jsval_release(v);
2818 if(FAILED(hres))
2819 return hres;
2821 if(b)
2822 jmp_next(ctx);
2823 else
2824 jmp_abs(ctx, arg);
2825 return S_OK;
2828 static HRESULT interp_pop(script_ctx_t *ctx)
2830 const unsigned arg = get_op_uint(ctx, 0);
2832 TRACE("%u\n", arg);
2834 stack_popn(ctx, arg);
2835 return S_OK;
2838 static HRESULT interp_ret(script_ctx_t *ctx)
2840 const unsigned clear_ret = get_op_uint(ctx, 0);
2841 call_frame_t *frame = ctx->call_ctx;
2843 TRACE("\n");
2845 if(clear_ret)
2846 jsval_release(steal_ret(frame));
2848 if((frame->flags & EXEC_CONSTRUCTOR) && !is_object_instance(frame->ret)) {
2849 jsval_release(frame->ret);
2850 IDispatch_AddRef(frame->this_obj);
2851 frame->ret = jsval_disp(frame->this_obj);
2854 jmp_abs(ctx, -1);
2855 return S_OK;
2858 static HRESULT interp_setret(script_ctx_t *ctx)
2860 call_frame_t *frame = ctx->call_ctx;
2862 TRACE("\n");
2864 jsval_release(frame->ret);
2865 frame->ret = stack_pop(ctx);
2866 return S_OK;
2869 static HRESULT interp_push_acc(script_ctx_t *ctx)
2871 HRESULT hres;
2873 TRACE("\n");
2875 hres = stack_push(ctx, ctx->acc);
2876 if(SUCCEEDED(hres))
2877 ctx->acc = jsval_undefined();
2878 return hres;
2881 typedef HRESULT (*op_func_t)(script_ctx_t*);
2883 static const op_func_t op_funcs[] = {
2884 #define X(x,a,b,c) interp_##x,
2885 OP_LIST
2886 #undef X
2889 static const unsigned op_move[] = {
2890 #define X(a,x,b,c) x,
2891 OP_LIST
2892 #undef X
2895 static void pop_call_frame(script_ctx_t *ctx)
2897 call_frame_t *frame = ctx->call_ctx;
2899 frame->stack_base -= frame->pop_locals + frame->pop_variables;
2901 assert(frame->scope == frame->base_scope);
2903 /* If current scope will be kept alive, we need to transfer local variables to its variable object. */
2904 if(frame->scope && frame->scope->ref > 1) {
2905 HRESULT hres = detach_variable_object(ctx, frame, TRUE);
2906 if(FAILED(hres))
2907 ERR("Failed to detach variable object: %08lx\n", hres);
2910 if(frame->arguments_obj)
2911 detach_arguments_object(frame->arguments_obj);
2912 if(frame->scope)
2913 scope_release(frame->scope);
2915 if(frame->pop_variables)
2916 stack_popn(ctx, frame->pop_variables);
2917 stack_popn(ctx, frame->pop_locals);
2919 ctx->call_ctx = frame->prev_frame;
2921 if(frame->function_instance)
2922 jsdisp_release(frame->function_instance);
2923 if(frame->variable_obj)
2924 jsdisp_release(frame->variable_obj);
2925 if(frame->this_obj)
2926 IDispatch_Release(frame->this_obj);
2927 jsval_release(frame->ret);
2928 release_bytecode(frame->bytecode);
2929 heap_free(frame);
2932 static void print_backtrace(script_ctx_t *ctx)
2934 unsigned depth = 0, i, line, char_pos;
2935 call_frame_t *frame;
2937 for(frame = ctx->call_ctx; frame; frame = frame->prev_frame) {
2938 WARN("%u\t", depth);
2939 depth++;
2941 if(frame->this_obj)
2942 WARN("%p->", frame->this_obj);
2943 WARN("%s(", frame->function->name ? debugstr_w(frame->function->name) : "[unnamed]");
2944 if(frame->base_scope && frame->base_scope->frame) {
2945 for(i=0; i < frame->argc; i++) {
2946 if(i < frame->function->param_cnt)
2947 WARN("%s%s=%s", i ? ", " : "", debugstr_w(frame->function->params[i]),
2948 debugstr_jsval(ctx->stack[local_off(frame, -i-1)]));
2949 else
2950 WARN("%s%s", i ? ", " : "", debugstr_jsval(ctx->stack[local_off(frame, -i-1)]));
2952 }else {
2953 WARN("[detached frame]");
2955 line = get_location_line(frame->bytecode, frame->bytecode->instrs[frame->ip].loc, &char_pos);
2956 WARN(") context %s line %u char %u\n", wine_dbgstr_longlong(frame->bytecode->source_context), line, char_pos);
2958 if(!(frame->flags & EXEC_RETURN_TO_INTERP)) {
2959 WARN("%u\t[native code]\n", depth);
2960 depth++;
2965 static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres)
2967 except_frame_t *except_frame;
2968 jsexcept_t *ei = ctx->ei;
2969 call_frame_t *frame;
2970 jsval_t except_val;
2971 unsigned catch_off;
2972 HRESULT hres;
2974 if(WARN_ON(jscript)) {
2975 jsdisp_t *error_obj;
2976 jsval_t msg;
2978 WARN("Exception %08lx %s", exception_hres, debugstr_jsval(ei->valid_value ? ei->value : jsval_undefined()));
2979 if(ei->valid_value && jsval_type(ei->value) == JSV_OBJECT) {
2980 error_obj = to_jsdisp(get_object(ei->value));
2981 if(error_obj) {
2982 hres = jsdisp_propget_name(error_obj, L"message", &msg);
2983 if(SUCCEEDED(hres)) {
2984 WARN(" (message %s)", debugstr_jsval(msg));
2985 jsval_release(msg);
2989 WARN(" in:\n");
2991 print_backtrace(ctx);
2994 frame = ctx->call_ctx;
2995 if(exception_hres != DISP_E_EXCEPTION)
2996 throw_error(ctx, exception_hres, NULL);
2997 set_error_location(ei, frame->bytecode, frame->bytecode->instrs[frame->ip].loc, IDS_RUNTIME_ERROR, NULL);
2999 while(!frame->except_frame) {
3000 DWORD flags;
3002 while(frame->scope != frame->base_scope)
3003 scope_pop(&frame->scope);
3005 stack_popn(ctx, ctx->stack_top-frame->stack_base);
3007 flags = frame->flags;
3008 pop_call_frame(ctx);
3009 if(!(flags & EXEC_RETURN_TO_INTERP))
3010 return DISP_E_EXCEPTION;
3011 frame = ctx->call_ctx;
3014 except_frame = frame->except_frame;
3015 catch_off = except_frame->catch_off;
3017 assert(except_frame->stack_top <= ctx->stack_top);
3018 stack_popn(ctx, ctx->stack_top - except_frame->stack_top);
3020 while(except_frame->scope != frame->scope)
3021 scope_pop(&frame->scope);
3023 frame->ip = catch_off ? catch_off : except_frame->finally_off;
3024 assert(!catch_off || frame->bytecode->instrs[frame->ip].op == OP_enter_catch);
3026 if(ei->valid_value) {
3027 except_val = ctx->ei->value;
3028 ei->valid_value = FALSE;
3029 }else {
3030 jsdisp_t *err;
3031 if(!(err = create_builtin_error(ctx)))
3032 return E_OUTOFMEMORY;
3033 except_val = jsval_obj(err);
3036 /* keep current except_frame if we're entering catch block with finally block associated */
3037 if(catch_off && except_frame->finally_off) {
3038 except_frame->catch_off = 0;
3039 }else {
3040 frame->except_frame = except_frame->next;
3041 heap_free(except_frame);
3044 hres = stack_push(ctx, except_val);
3045 if(FAILED(hres))
3046 return hres;
3048 if(!catch_off)
3049 hres = stack_push(ctx, jsval_bool(FALSE));
3050 return hres;
3053 static HRESULT enter_bytecode(script_ctx_t *ctx, jsval_t *r)
3055 call_frame_t *frame;
3056 jsop_t op;
3057 HRESULT hres = S_OK;
3059 TRACE("\n");
3061 while(1) {
3062 frame = ctx->call_ctx;
3063 op = frame->bytecode->instrs[frame->ip].op;
3064 hres = op_funcs[op](ctx);
3065 if(FAILED(hres)) {
3066 hres = unwind_exception(ctx, hres);
3067 if(FAILED(hres))
3068 return hres;
3069 }else if(frame->ip == -1) {
3070 const DWORD return_to_interp = frame->flags & EXEC_RETURN_TO_INTERP;
3072 assert(ctx->stack_top == frame->stack_base);
3073 assert(frame->scope == frame->base_scope);
3075 if(return_to_interp) {
3076 jsval_release(ctx->acc);
3077 ctx->acc = steal_ret(frame);
3078 }else if(r) {
3079 *r = steal_ret(frame);
3081 pop_call_frame(ctx);
3082 if(!return_to_interp)
3083 break;
3084 }else {
3085 frame->ip += op_move[op];
3089 return S_OK;
3092 static HRESULT bind_event_target(script_ctx_t *ctx, function_code_t *func, jsdisp_t *func_obj)
3094 IBindEventHandler *target;
3095 exprval_t exprval;
3096 IDispatch *disp;
3097 jsval_t v;
3098 HRESULT hres;
3100 hres = identifier_eval(ctx, func->event_target, &exprval);
3101 if(FAILED(hres))
3102 return hres;
3104 hres = exprval_to_value(ctx, &exprval, &v);
3105 if(FAILED(hres))
3106 return hres;
3108 if(!is_object_instance(v)) {
3109 FIXME("Can't bind to %s\n", debugstr_jsval(v));
3110 jsval_release(v);
3113 disp = get_object(v);
3114 hres = IDispatch_QueryInterface(disp, &IID_IBindEventHandler, (void**)&target);
3115 if(SUCCEEDED(hres)) {
3116 hres = IBindEventHandler_BindHandler(target, func->name, (IDispatch*)&func_obj->IDispatchEx_iface);
3117 IBindEventHandler_Release(target);
3118 if(FAILED(hres))
3119 WARN("BindEvent failed: %08lx\n", hres);
3120 }else {
3121 FIXME("No IBindEventHandler, not yet supported binding\n");
3124 IDispatch_Release(disp);
3125 return hres;
3128 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)
3130 const unsigned orig_stack = ctx->stack_top;
3131 scope_chain_t *scope;
3132 unsigned i;
3133 jsval_t v;
3134 HRESULT hres;
3136 /* If arguments are already on the stack, we may use them. */
3137 if(argv + argc == ctx->stack + ctx->stack_top) {
3138 frame->arguments_off = argv - ctx->stack;
3139 i = argc;
3140 }else {
3141 frame->arguments_off = ctx->stack_top;
3142 for(i = 0; i < argc; i++) {
3143 hres = jsval_copy(argv[i], &v);
3144 if(SUCCEEDED(hres))
3145 hres = stack_push(ctx, v);
3146 if(FAILED(hres)) {
3147 stack_popn(ctx, i);
3148 return hres;
3153 /* If fewer than declared arguments were passed, fill remaining with undefined value. */
3154 for(; i < frame->function->param_cnt; i++) {
3155 hres = stack_push(ctx, jsval_undefined());
3156 if(FAILED(hres)) {
3157 stack_popn(ctx, ctx->stack_top - orig_stack);
3158 return hres;
3162 frame->pop_locals = ctx->stack_top - orig_stack;
3164 frame->variables_off = ctx->stack_top;
3166 for(i = 0; i < frame->function->var_cnt; i++) {
3167 hres = stack_push(ctx, jsval_undefined());
3168 if(FAILED(hres)) {
3169 stack_popn(ctx, ctx->stack_top - orig_stack);
3170 return hres;
3174 frame->pop_variables = i;
3176 hres = scope_push(scope_chain, variable_object, to_disp(variable_object), &scope);
3177 if(FAILED(hres)) {
3178 stack_popn(ctx, ctx->stack_top - orig_stack);
3179 return hres;
3182 for(i = 0; i < frame->function->func_cnt; i++) {
3183 if(frame->function->funcs[i].local_ref != INVALID_LOCAL_REF
3184 && !frame->function->funcs[i].scope_index)
3186 jsdisp_t *func_obj;
3187 unsigned off;
3189 hres = create_source_function(ctx, frame->bytecode, frame->function->funcs+i, scope, &func_obj);
3190 if(FAILED(hres)) {
3191 stack_popn(ctx, ctx->stack_top - orig_stack);
3192 scope_release(scope);
3193 return hres;
3196 off = local_off(frame, frame->function->funcs[i].local_ref);
3197 jsval_release(ctx->stack[off]);
3198 ctx->stack[off] = jsval_obj(func_obj);
3202 scope->frame = frame;
3203 frame->base_scope = frame->scope = scope;
3204 return S_OK;
3207 HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, function_code_t *function, scope_chain_t *scope,
3208 IDispatch *this_obj, jsdisp_t *function_instance, unsigned argc, jsval_t *argv, jsval_t *r)
3210 jsdisp_t *variable_obj;
3211 call_frame_t *frame;
3212 unsigned i;
3213 HRESULT hres;
3215 if(!ctx->stack) {
3216 ctx->stack = heap_alloc(stack_size * sizeof(*ctx->stack));
3217 if(!ctx->stack)
3218 return E_OUTOFMEMORY;
3221 if(bytecode->named_item) {
3222 if(!bytecode->named_item->script_obj) {
3223 hres = create_named_item_script_obj(ctx, bytecode->named_item);
3224 if(FAILED(hres)) return hres;
3228 if(!ctx->ei->enter_notified) {
3229 ctx->ei->enter_notified = TRUE;
3230 IActiveScriptSite_OnEnterScript(ctx->site);
3233 for(i = 0; i < function->func_cnt; i++) {
3234 jsdisp_t *func_obj;
3236 if(!function->funcs[i].event_target)
3237 continue;
3239 if (function->funcs[i].scope_index)
3241 /* TODO: Add tests and handle in interp_push_scope(). */
3242 FIXME("Event target with scope index are not properly handled.\n");
3245 hres = create_source_function(ctx, bytecode, function->funcs+i, scope, &func_obj);
3246 if(FAILED(hres))
3247 return hres;
3249 hres = bind_event_target(ctx, function->funcs+i, func_obj);
3250 jsdisp_release(func_obj);
3251 if(FAILED(hres))
3252 return hres;
3255 if((flags & EXEC_EVAL) && ctx->call_ctx) {
3256 variable_obj = jsdisp_addref(ctx->call_ctx->variable_obj);
3257 }else if(!(flags & (EXEC_GLOBAL | EXEC_EVAL))) {
3258 hres = create_dispex(ctx, NULL, NULL, &variable_obj);
3259 if(FAILED(hres)) return hres;
3260 }else if(bytecode->named_item) {
3261 variable_obj = jsdisp_addref(bytecode->named_item->script_obj);
3262 }else {
3263 variable_obj = jsdisp_addref(ctx->global);
3266 if(flags & (EXEC_GLOBAL | EXEC_EVAL)) {
3267 named_item_t *item = bytecode->named_item;
3268 DISPID id;
3270 for(i=0; i < function->var_cnt; i++) {
3271 TRACE("[%d] %s %d\n", i, debugstr_w(function->variables[i].name), function->variables[i].func_id);
3272 if(function->variables[i].func_id != -1) {
3273 jsdisp_t *func_obj;
3275 if (function->funcs[function->variables[i].func_id].scope_index && flags & EXEC_EVAL)
3277 /* TODO: Add tests and handle in interp_push_scope(). */
3278 FIXME("Functions with scope index inside eval() are not properly handled.\n");
3281 hres = create_source_function(ctx, bytecode, function->funcs+function->variables[i].func_id, scope, &func_obj);
3282 if(FAILED(hres))
3283 goto fail;
3285 hres = jsdisp_propput_name(variable_obj, function->variables[i].name, jsval_obj(func_obj));
3286 jsdisp_release(func_obj);
3287 continue;
3290 if(item && !(item->flags & SCRIPTITEM_CODEONLY)
3291 && SUCCEEDED(disp_get_id(ctx, item->disp, function->variables[i].name, function->variables[i].name, 0, &id)))
3292 continue;
3294 if(!item && (flags & EXEC_GLOBAL) && lookup_global_members(ctx, function->variables[i].name, NULL))
3295 continue;
3297 hres = jsdisp_get_id(variable_obj, function->variables[i].name, fdexNameEnsure, &id);
3298 if(FAILED(hres))
3299 goto fail;
3303 /* ECMA-262 3rd Edition 11.2.3.7 */
3304 if(this_obj) {
3305 jsdisp_t *jsthis;
3307 jsthis = iface_to_jsdisp(this_obj);
3308 if(jsthis) {
3309 if(jsthis->builtin_info->class == JSCLASS_GLOBAL || jsthis->builtin_info->class == JSCLASS_NONE)
3310 this_obj = NULL;
3311 jsdisp_release(jsthis);
3315 if(ctx->call_ctx && (flags & EXEC_EVAL)) {
3316 hres = detach_variable_object(ctx, ctx->call_ctx, FALSE);
3317 if(FAILED(hres))
3318 goto fail;
3321 frame = heap_alloc_zero(sizeof(*frame));
3322 if(!frame) {
3323 hres = E_OUTOFMEMORY;
3324 goto fail;
3327 frame->function = function;
3328 frame->ret = jsval_undefined();
3329 frame->argc = argc;
3330 frame->bytecode = bytecode_addref(bytecode);
3332 if(!(flags & (EXEC_GLOBAL|EXEC_EVAL))) {
3333 hres = setup_scope(ctx, frame, scope, variable_obj, argc, argv);
3334 if(FAILED(hres)) {
3335 release_bytecode(frame->bytecode);
3336 heap_free(frame);
3337 goto fail;
3339 }else if(scope) {
3340 frame->base_scope = frame->scope = scope_addref(scope);
3343 frame->ip = function->instr_off;
3344 frame->stack_base = ctx->stack_top;
3345 if(this_obj) {
3346 frame->this_obj = this_obj;
3347 IDispatch_AddRef(frame->this_obj);
3350 if(function_instance)
3351 frame->function_instance = jsdisp_addref(function_instance);
3353 frame->flags = flags;
3354 frame->variable_obj = variable_obj;
3356 frame->prev_frame = ctx->call_ctx;
3357 ctx->call_ctx = frame;
3359 if(flags & EXEC_RETURN_TO_INTERP) {
3361 * We're called directly from interpreter, so we may just setup call frame and return.
3362 * Already running interpreter will take care of execution.
3364 if(r)
3365 *r = jsval_undefined();
3366 return S_OK;
3369 return enter_bytecode(ctx, r);
3371 fail:
3372 jsdisp_release(variable_obj);
3373 return hres;