jscript: Store ref to scope directly instead of frame in arguments object.
[wine.git] / dlls / jscript / engine.c
blob379d209f0b068ddb3b0d8d2ecb45244c72fdcd7a
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 static jsval_t *get_detached_var_ref(scope_chain_t *scope, const WCHAR *name)
167 struct vars_buffer *detached_vars = scope->detached_vars;
168 local_ref_t *ref;
170 if(!detached_vars)
171 return NULL;
172 ref = lookup_local(detached_vars->func_code, name, scope->scope_index);
173 return ref && ref->ref < 0 ? &detached_vars->var[-ref->ref - 1] : NULL;
176 static HRESULT get_detached_var_dispid(scope_chain_t *scope, const WCHAR *name, DISPID *id)
178 jsval_t *var_ref = get_detached_var_ref(scope, name);
179 return var_ref ? jsdisp_get_idx_id(&scope->dispex, var_ref - scope->detached_vars->var, id) : DISP_E_UNKNOWNNAME;
182 /* Steals input reference even on failure. */
183 static HRESULT stack_push_exprval(script_ctx_t *ctx, exprval_t *val)
185 HRESULT hres;
187 switch(val->type) {
188 case EXPRVAL_JSVAL:
189 hres = stack_push(ctx, jsval_null());
190 if(SUCCEEDED(hres))
191 hres = stack_push(ctx, val->u.val);
192 return hres;
193 case EXPRVAL_IDREF:
194 hres = stack_push(ctx, jsval_disp(val->u.idref.disp));
195 if(SUCCEEDED(hres))
196 hres = stack_push(ctx, jsval_number(val->u.idref.id));
197 else
198 IDispatch_Release(val->u.idref.disp);
199 return hres;
200 case EXPRVAL_STACK_REF:
201 hres = stack_push(ctx, jsval_number(val->u.off));
202 if(SUCCEEDED(hres))
203 hres = stack_push(ctx, jsval_undefined());
204 return hres;
205 case EXPRVAL_INVALID:
206 hres = stack_push(ctx, jsval_undefined());
207 if(SUCCEEDED(hres))
208 hres = stack_push(ctx, jsval_number(val->u.hres));
209 return hres;
212 assert(0);
213 return E_FAIL;
216 static BOOL stack_topn_exprval(script_ctx_t *ctx, unsigned n, exprval_t *r)
218 jsval_t v = stack_topn(ctx, n+1);
220 switch(jsval_type(v)) {
221 case JSV_NUMBER: {
222 call_frame_t *frame = ctx->call_ctx;
223 scope_chain_t *scope;
224 unsigned off = get_number(v);
226 if(!frame->base_scope->frame && off >= frame->arguments_off) {
227 jsdisp_t *jsobj;
228 DISPID id;
229 BSTR name;
230 HRESULT hres = E_FAIL;
232 /* Got stack reference in deoptimized code. Need to convert it back to variable object reference. */
234 assert(off < frame->variables_off + frame->function->var_cnt);
235 if (off >= frame->variables_off)
237 name = frame->function->variables[off - frame->variables_off].name;
238 scope = frame->scope;
240 else
242 name = frame->function->params[off - frame->arguments_off];
243 scope = frame->base_scope;
246 while (1)
248 hres = get_detached_var_dispid(scope, name, &id);
249 if (hres != DISP_E_UNKNOWNNAME)
251 if (FAILED(hres))
253 r->type = EXPRVAL_INVALID;
254 r->u.hres = hres;
255 return FALSE;
257 jsobj = &scope->dispex;
258 break;
260 if ((jsobj = to_jsdisp(scope->obj)) && SUCCEEDED(hres = jsdisp_get_id(jsobj, name, 0, &id)))
261 break;
262 if (scope == frame->base_scope)
264 r->type = EXPRVAL_INVALID;
265 r->u.hres = hres;
266 return FALSE;
268 scope = scope->next;
271 *stack_top_ref(ctx, n+1) = jsval_obj(jsdisp_addref(jsobj));
272 *stack_top_ref(ctx, n) = jsval_number(id);
273 r->type = EXPRVAL_IDREF;
274 r->u.idref.disp = to_disp(jsobj);
275 r->u.idref.id = id;
276 return TRUE;
279 r->type = EXPRVAL_STACK_REF;
280 r->u.off = off;
281 return TRUE;
283 case JSV_OBJECT:
284 r->type = EXPRVAL_IDREF;
285 r->u.idref.disp = get_object(v);
286 assert(is_number(stack_topn(ctx, n)));
287 r->u.idref.id = get_number(stack_topn(ctx, n));
288 return TRUE;
289 case JSV_UNDEFINED:
290 r->type = EXPRVAL_INVALID;
291 assert(is_number(stack_topn(ctx, n)));
292 r->u.hres = get_number(stack_topn(ctx, n));
293 return FALSE;
294 case JSV_NULL:
295 r->type = EXPRVAL_JSVAL;
296 r->u.val = stack_topn(ctx, n);
297 return TRUE;
298 default:
299 assert(0);
300 return FALSE;
304 static inline BOOL stack_pop_exprval(script_ctx_t *ctx, exprval_t *r)
306 BOOL ret = stack_topn_exprval(ctx, 0, r);
307 ctx->stack_top -= 2;
308 return ret;
311 static HRESULT exprval_propput(script_ctx_t *ctx, exprval_t *ref, jsval_t v)
313 switch(ref->type) {
314 case EXPRVAL_STACK_REF: {
315 jsval_t *r = ctx->stack + ref->u.off;
316 jsval_release(*r);
317 return jsval_copy(v, r);
319 case EXPRVAL_IDREF:
320 return disp_propput(ctx, ref->u.idref.disp, ref->u.idref.id, v);
321 case EXPRVAL_JSVAL:
322 WARN("ignoring an attempt to set value reference\n");
323 return S_OK;
324 default:
325 assert(0);
326 return E_FAIL;
330 static HRESULT exprval_propget(script_ctx_t *ctx, exprval_t *ref, jsval_t *r)
332 switch(ref->type) {
333 case EXPRVAL_STACK_REF:
334 return jsval_copy(ctx->stack[ref->u.off], r);
335 case EXPRVAL_IDREF:
336 return disp_propget(ctx, ref->u.idref.disp, ref->u.idref.id, r);
337 case EXPRVAL_JSVAL:
338 return jsval_copy(ref->u.val, r);
339 default:
340 assert(0);
341 return E_FAIL;
345 static HRESULT exprval_call(script_ctx_t *ctx, exprval_t *ref, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
347 jsdisp_t *jsdisp;
348 HRESULT hres;
349 jsval_t v;
351 switch(ref->type) {
352 case EXPRVAL_STACK_REF: {
353 v = ctx->stack[ref->u.off];
355 if(!is_object_instance(v)) {
356 FIXME("invoke %s\n", debugstr_jsval(v));
357 return E_FAIL;
360 return disp_call_value(ctx, get_object(v), jsval_undefined(), flags, argc, argv, r);
362 case EXPRVAL_IDREF:
363 /* ECMA-262 3rd Edition 11.2.3.7 / ECMA-262 5.1 Edition 11.2.3.6 *
364 * Don't treat scope object props as PropertyReferences. */
365 if((jsdisp = to_jsdisp(ref->u.idref.disp)) && jsdisp->builtin_info->class == JSCLASS_NONE) {
366 hres = disp_propget(ctx, ref->u.idref.disp, ref->u.idref.id, &v);
367 if(FAILED(hres))
368 return hres;
369 if(!is_object_instance(v)) {
370 FIXME("invoke %s\n", debugstr_jsval(v));
371 hres = E_FAIL;
372 }else {
373 hres = disp_call_value(ctx, get_object(v), jsval_undefined(), flags, argc, argv, r);
375 jsval_release(v);
376 return hres;
378 return disp_call(ctx, ref->u.idref.disp, ref->u.idref.id, flags, argc, argv, r);
379 case EXPRVAL_JSVAL: {
380 IDispatch *obj;
382 hres = to_object(ctx, ref->u.val, &obj);
383 if(SUCCEEDED(hres)) {
384 hres = disp_call_value(ctx, obj, jsval_undefined(), flags, argc, argv, r);
385 IDispatch_Release(obj);
387 return hres;
389 default:
390 assert(0);
391 return E_FAIL;
395 /* ECMA-262 3rd Edition 8.7.1 */
396 /* Steals input reference. */
397 static HRESULT exprval_to_value(script_ctx_t *ctx, exprval_t *ref, jsval_t *r)
399 HRESULT hres;
401 if(ref->type == EXPRVAL_JSVAL) {
402 *r = ref->u.val;
403 return S_OK;
406 hres = exprval_propget(ctx, ref, r);
408 if(ref->type == EXPRVAL_IDREF)
409 IDispatch_Release(ref->u.idref.disp);
410 return hres;
413 static void exprval_release(exprval_t *val)
415 switch(val->type) {
416 case EXPRVAL_JSVAL:
417 jsval_release(val->u.val);
418 return;
419 case EXPRVAL_IDREF:
420 if(val->u.idref.disp)
421 IDispatch_Release(val->u.idref.disp);
422 return;
423 case EXPRVAL_STACK_REF:
424 case EXPRVAL_INVALID:
425 return;
429 static inline void exprval_set_exception(exprval_t *val, HRESULT hres)
431 val->type = EXPRVAL_INVALID;
432 val->u.hres = hres;
435 static inline void exprval_set_disp_ref(exprval_t *ref, IDispatch *obj, DISPID id)
437 ref->type = EXPRVAL_IDREF;
438 IDispatch_AddRef(ref->u.idref.disp = obj);
439 ref->u.idref.id = id;
442 static inline jsval_t steal_ret(call_frame_t *frame)
444 jsval_t r = frame->ret;
445 frame->ret = jsval_undefined();
446 return r;
449 static inline void clear_acc(script_ctx_t *ctx)
451 jsval_release(ctx->acc);
452 ctx->acc = jsval_undefined();
455 static inline scope_chain_t *scope_from_dispex(jsdisp_t *dispex)
457 return CONTAINING_RECORD(dispex, scope_chain_t, dispex);
460 static void scope_destructor(jsdisp_t *dispex)
462 scope_chain_t *scope = scope_from_dispex(dispex);
464 if(scope->detached_vars) {
465 struct vars_buffer *vars = scope->detached_vars;
466 unsigned i, cnt = vars->argc;
468 release_bytecode(vars->func_code->bytecode);
469 for(i = 0; i < cnt; i++)
470 jsval_release(vars->var[i]);
471 free(vars);
474 if(scope->next)
475 scope_release(scope->next);
477 if(scope->obj)
478 IDispatch_Release(scope->obj);
479 free(scope);
482 static unsigned scope_idx_length(jsdisp_t *dispex)
484 scope_chain_t *scope = scope_from_dispex(dispex);
486 return scope->detached_vars->argc;
489 static HRESULT scope_idx_get(jsdisp_t *dispex, unsigned idx, jsval_t *r)
491 scope_chain_t *scope = scope_from_dispex(dispex);
493 return jsval_copy(scope->detached_vars->var[idx], r);
496 static HRESULT scope_idx_put(jsdisp_t *dispex, unsigned idx, jsval_t val)
498 scope_chain_t *scope = scope_from_dispex(dispex);
499 jsval_t copy, *ref;
500 HRESULT hres;
502 hres = jsval_copy(val, &copy);
503 if(FAILED(hres))
504 return hres;
506 ref = &scope->detached_vars->var[idx];
507 jsval_release(*ref);
508 *ref = copy;
509 return S_OK;
512 static HRESULT scope_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex)
514 scope_chain_t *scope = scope_from_dispex(dispex);
515 jsdisp_t *jsobj;
516 HRESULT hres;
518 if(scope->detached_vars) {
519 struct vars_buffer *vars = scope->detached_vars;
520 unsigned i, cnt = vars->argc;
522 for(i = 0; i < cnt; i++) {
523 hres = gc_process_linked_val(gc_ctx, op, dispex, &vars->var[i]);
524 if(FAILED(hres))
525 return hres;
529 if(scope->next) {
530 hres = gc_process_linked_obj(gc_ctx, op, dispex, &scope->next->dispex, (void**)&scope->next);
531 if(FAILED(hres))
532 return hres;
535 if(op == GC_TRAVERSE_UNLINK) {
536 IDispatch *obj = scope->obj;
537 if(obj) {
538 scope->obj = NULL;
539 IDispatch_Release(obj);
541 return S_OK;
544 return scope->obj && (jsobj = to_jsdisp(scope->obj)) ? gc_process_linked_obj(gc_ctx, op, dispex, jsobj, (void**)&scope->obj) : S_OK;
547 static const builtin_info_t scope_info = {
548 JSCLASS_NONE,
549 NULL,
551 NULL,
552 scope_destructor,
553 NULL,
554 scope_idx_length,
555 scope_idx_get,
556 scope_idx_put,
557 scope_gc_traverse
560 static HRESULT scope_push(script_ctx_t *ctx, scope_chain_t *scope, IDispatch *obj, scope_chain_t **ret)
562 scope_chain_t *new_scope;
563 HRESULT hres;
565 new_scope = calloc(1, sizeof(scope_chain_t));
566 if(!new_scope)
567 return E_OUTOFMEMORY;
569 hres = init_dispex(&new_scope->dispex, ctx, &scope_info, NULL);
570 if(FAILED(hres)) {
571 free(new_scope);
572 return hres;
575 if (obj)
576 IDispatch_AddRef(obj);
577 new_scope->obj = obj;
578 new_scope->frame = NULL;
579 new_scope->next = scope ? scope_addref(scope) : NULL;
580 new_scope->scope_index = 0;
582 *ret = new_scope;
583 return S_OK;
586 static void scope_pop(scope_chain_t **scope)
588 scope_chain_t *tmp;
590 tmp = *scope;
591 *scope = tmp->next;
592 scope_release(tmp);
595 static HRESULT disp_get_id(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name, BSTR name_bstr, DWORD flags, DISPID *id)
597 IDispatchEx *dispex;
598 jsdisp_t *jsdisp;
599 BSTR bstr;
600 HRESULT hres;
602 jsdisp = to_jsdisp(disp);
603 if(jsdisp)
604 return jsdisp_get_id(jsdisp, name, flags, id);
606 if(name_bstr) {
607 bstr = name_bstr;
608 }else {
609 bstr = SysAllocString(name);
610 if(!bstr)
611 return E_OUTOFMEMORY;
614 *id = 0;
615 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
616 if(SUCCEEDED(hres)) {
617 hres = IDispatchEx_GetDispID(dispex, bstr, make_grfdex(ctx, flags|fdexNameCaseSensitive), id);
618 IDispatchEx_Release(dispex);
619 }else {
620 TRACE("using IDispatch\n");
621 hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, id);
624 if(name_bstr != bstr)
625 SysFreeString(bstr);
626 return hres;
629 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, BOOL *ret)
631 IObjectIdentity *identity;
632 IUnknown *unk1, *unk2;
633 HRESULT hres;
635 if(disp1 == disp2) {
636 *ret = TRUE;
637 return S_OK;
640 if(!disp1 || !disp2) {
641 *ret = FALSE;
642 return S_OK;
645 hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
646 if(FAILED(hres))
647 return hres;
649 hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
650 if(FAILED(hres)) {
651 IUnknown_Release(unk1);
652 return hres;
655 if(unk1 == unk2) {
656 *ret = TRUE;
657 }else {
658 hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
659 if(SUCCEEDED(hres)) {
660 hres = IObjectIdentity_IsEqualObject(identity, unk2);
661 IObjectIdentity_Release(identity);
662 *ret = hres == S_OK;
663 }else {
664 *ret = FALSE;
668 IUnknown_Release(unk1);
669 IUnknown_Release(unk2);
670 return S_OK;
673 /* ECMA-262 3rd Edition 11.9.6 */
674 HRESULT jsval_strict_equal(jsval_t lval, jsval_t rval, BOOL *ret)
676 jsval_type_t type = jsval_type(lval);
678 TRACE("\n");
680 if(type != jsval_type(rval)) {
681 *ret = FALSE;
682 return S_OK;
685 switch(type) {
686 case JSV_UNDEFINED:
687 case JSV_NULL:
688 *ret = TRUE;
689 break;
690 case JSV_OBJECT:
691 return disp_cmp(get_object(lval), get_object(rval), ret);
692 case JSV_STRING:
693 *ret = jsstr_eq(get_string(lval), get_string(rval));
694 break;
695 case JSV_NUMBER:
696 *ret = get_number(lval) == get_number(rval);
697 break;
698 case JSV_BOOL:
699 *ret = !get_bool(lval) == !get_bool(rval);
700 break;
701 case JSV_VARIANT:
702 WARN("VARIANT type, returning false\n");
703 *ret = FALSE;
704 return S_OK;
707 return S_OK;
710 static HRESULT alloc_detached_vars(script_ctx_t *ctx, call_frame_t *frame, scope_chain_t *scope)
712 function_code_t *func = frame->function;
713 unsigned i, argc;
715 argc = (scope == frame->base_scope) ? max(frame->argc, func->param_cnt) : 0;
716 if(!argc)
717 return S_OK;
719 if(!(scope->detached_vars = malloc(FIELD_OFFSET(struct vars_buffer, var[argc]))))
720 return E_OUTOFMEMORY;
721 scope->detached_vars->argc = argc;
722 scope->detached_vars->func_code = func;
723 bytecode_addref(func->bytecode);
725 for(i = 0; i < argc; i++) {
726 scope->detached_vars->var[i] = ctx->stack[frame->arguments_off + i];
727 ctx->stack[frame->arguments_off + i] = jsval_undefined();
730 return S_OK;
733 static HRESULT detach_scope(script_ctx_t *ctx, call_frame_t *frame, scope_chain_t *scope)
735 function_code_t *func = frame->function;
736 unsigned int i, index;
737 jsdisp_t *jsobj;
738 HRESULT hres;
740 if (!scope->frame)
741 return S_OK;
743 assert(scope->frame == frame);
744 scope->frame = NULL;
746 hres = alloc_detached_vars(ctx, frame, scope);
747 if (FAILED(hres))
748 return hres;
750 if (!scope->obj)
752 if (FAILED(hres = create_object(ctx, NULL, &jsobj)))
753 return hres;
754 scope->obj = to_disp(jsobj);
756 else
757 jsobj = as_jsdisp(scope->obj);
759 if (scope == frame->base_scope && func->name && func->local_ref == INVALID_LOCAL_REF &&
760 ctx->version >= SCRIPTLANGUAGEVERSION_ES5)
761 jsdisp_propput_name(jsobj, func->name, jsval_obj(jsdisp_addref(frame->function_instance)));
763 index = scope->scope_index;
764 for(i = 0; i < frame->function->local_scopes[index].locals_cnt; i++)
766 WCHAR *name = frame->function->local_scopes[index].locals[i].name;
767 int ref = frame->function->local_scopes[index].locals[i].ref;
769 if (ref < 0)
770 continue;
771 if (FAILED(hres = jsdisp_propput_name(jsobj, name, ctx->stack[local_off(frame, ref)])))
772 return hres;
773 if (scope != frame->base_scope && frame->function->variables[ref].func_id != -1
774 && FAILED(hres = jsdisp_propput_name(frame->variable_obj, name, ctx->stack[local_off(frame, ref)])))
775 return hres;
777 return S_OK;
780 static HRESULT detach_scope_chain(script_ctx_t *ctx, call_frame_t *frame, scope_chain_t *scope)
782 HRESULT hres;
784 if (scope != frame->base_scope && FAILED(hres = detach_scope_chain(ctx, frame, scope->next)))
785 return hres;
786 return detach_scope(ctx, frame, scope);
790 * Transfers local variables from stack to variable object.
791 * It's slow, so we want to avoid it as much as possible.
793 static HRESULT detach_variable_object(script_ctx_t *ctx, call_frame_t *frame, BOOL from_release)
795 HRESULT hres;
797 if(!frame->base_scope || !frame->base_scope->frame)
798 return S_OK;
800 TRACE("detaching %p\n", frame);
802 assert(frame == frame->base_scope->frame);
803 assert(to_disp(frame->variable_obj) == frame->base_scope->obj);
805 if(!from_release && !frame->arguments_obj) {
806 hres = setup_arguments_object(ctx, frame);
807 if(FAILED(hres))
808 return hres;
811 TRACE("detaching scope chain %p, frame %p.\n", ctx->call_ctx->scope, frame);
812 return detach_scope_chain(ctx, frame, ctx->call_ctx->scope);
815 static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
817 named_item_t *item;
818 DISPID id;
819 HRESULT hres;
821 LIST_FOR_EACH_ENTRY(item, &ctx->named_items, named_item_t, entry) {
822 if(item->flags & SCRIPTITEM_GLOBALMEMBERS) {
823 hres = disp_get_id(ctx, item->disp, identifier, identifier, 0, &id);
824 if(SUCCEEDED(hres)) {
825 if(ret)
826 exprval_set_disp_ref(ret, item->disp, id);
827 return TRUE;
832 return FALSE;
835 IDispatch *lookup_global_host(script_ctx_t *ctx)
837 IDispatch *disp = NULL;
838 named_item_t *item;
840 LIST_FOR_EACH_ENTRY(item, &ctx->named_items, named_item_t, entry) {
841 if(!(item->flags & SCRIPTITEM_GLOBALMEMBERS)) continue;
842 disp = item->disp;
843 break;
845 if(!disp) disp = to_disp(ctx->global);
847 return disp;
850 static int __cdecl local_ref_cmp(const void *key, const void *ref)
852 return wcscmp((const WCHAR*)key, ((const local_ref_t*)ref)->name);
855 local_ref_t *lookup_local(const function_code_t *function, const WCHAR *identifier, unsigned int scope)
857 return bsearch(identifier, function->local_scopes[scope].locals, function->local_scopes[scope].locals_cnt,
858 sizeof(*function->local_scopes[scope].locals), local_ref_cmp);
861 /* ECMA-262 3rd Edition 10.1.4 */
862 static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
864 scope_chain_t *scope;
865 named_item_t *item;
866 DISPID id = 0;
867 HRESULT hres;
869 TRACE("%s\n", debugstr_w(identifier));
871 if(ctx->call_ctx) {
872 for(scope = ctx->call_ctx->scope; scope; scope = scope->next) {
873 if(scope->frame) {
874 function_code_t *func = scope->frame->function;
875 local_ref_t *ref = lookup_local(func, identifier, scope->scope_index);
877 if(ref) {
878 ret->type = EXPRVAL_STACK_REF;
879 ret->u.off = local_off(scope->frame, ref->ref);
880 TRACE("returning ref %d for %d\n", ret->u.off, ref->ref);
881 return S_OK;
884 if(!wcscmp(identifier, L"arguments")) {
885 hres = detach_variable_object(ctx, scope->frame, FALSE);
886 if(FAILED(hres))
887 return hres;
890 /* ECMA-262 5.1 Edition 13 */
891 if(func->name && ctx->version >= SCRIPTLANGUAGEVERSION_ES5 &&
892 func->local_ref == INVALID_LOCAL_REF && !wcscmp(identifier, func->name)) {
893 TRACE("returning a function from scope chain\n");
894 ret->type = EXPRVAL_JSVAL;
895 ret->u.val = jsval_obj(jsdisp_addref(scope->frame->function_instance));
896 return S_OK;
898 }else if((hres = get_detached_var_dispid(scope, identifier, &id)) != DISP_E_UNKNOWNNAME) {
899 if(SUCCEEDED(hres))
900 exprval_set_disp_ref(ret, to_disp(&scope->dispex), id);
901 return hres;
904 if (!scope->obj)
905 continue;
907 hres = disp_get_id(ctx, scope->obj, identifier, identifier, fdexNameImplicit, &id);
908 if(SUCCEEDED(hres)) {
909 exprval_set_disp_ref(ret, scope->obj, id);
910 return S_OK;
914 item = ctx->call_ctx->bytecode->named_item;
915 if(item) {
916 hres = jsdisp_get_id(item->script_obj, identifier, 0, &id);
917 if(SUCCEEDED(hres)) {
918 exprval_set_disp_ref(ret, to_disp(item->script_obj), id);
919 return S_OK;
921 if(!(item->flags & SCRIPTITEM_CODEONLY)) {
922 hres = disp_get_id(ctx, item->disp, identifier, identifier, 0, &id);
923 if(SUCCEEDED(hres)) {
924 exprval_set_disp_ref(ret, item->disp, id);
925 return S_OK;
931 hres = jsdisp_get_id(ctx->global, identifier, 0, &id);
932 if(SUCCEEDED(hres)) {
933 exprval_set_disp_ref(ret, to_disp(ctx->global), id);
934 return S_OK;
937 item = lookup_named_item(ctx, identifier, SCRIPTITEM_ISVISIBLE);
938 if(item) {
939 IDispatch_AddRef(item->disp);
940 ret->type = EXPRVAL_JSVAL;
941 ret->u.val = jsval_disp(item->disp);
942 return S_OK;
945 if(lookup_global_members(ctx, identifier, ret))
946 return S_OK;
948 exprval_set_exception(ret, JS_E_UNDEFINED_VARIABLE);
949 return S_OK;
952 static inline BSTR get_op_bstr(script_ctx_t *ctx, int i)
954 call_frame_t *frame = ctx->call_ctx;
955 return frame->bytecode->instrs[frame->ip].u.arg[i].bstr;
958 static inline unsigned get_op_uint(script_ctx_t *ctx, int i)
960 call_frame_t *frame = ctx->call_ctx;
961 return frame->bytecode->instrs[frame->ip].u.arg[i].uint;
964 static inline unsigned get_op_int(script_ctx_t *ctx, int i)
966 call_frame_t *frame = ctx->call_ctx;
967 return frame->bytecode->instrs[frame->ip].u.arg[i].lng;
970 static inline jsstr_t *get_op_str(script_ctx_t *ctx, int i)
972 call_frame_t *frame = ctx->call_ctx;
973 return frame->bytecode->instrs[frame->ip].u.arg[i].str;
976 static inline double get_op_double(script_ctx_t *ctx)
978 call_frame_t *frame = ctx->call_ctx;
979 return frame->bytecode->instrs[frame->ip].u.dbl;
982 static inline void jmp_next(script_ctx_t *ctx)
984 ctx->call_ctx->ip++;
987 static inline void jmp_abs(script_ctx_t *ctx, unsigned dst)
989 ctx->call_ctx->ip = dst;
992 /* ECMA-262 3rd Edition 12.6.4 */
993 static HRESULT interp_forin(script_ctx_t *ctx)
995 const HRESULT arg = get_op_uint(ctx, 0);
996 IDispatch *obj = NULL;
997 IDispatchEx *dispex;
998 exprval_t prop_ref;
999 DISPID id;
1000 BSTR name = NULL;
1001 HRESULT hres;
1003 TRACE("\n");
1005 assert(is_number(stack_top(ctx)));
1006 id = get_number(stack_top(ctx));
1008 if(!stack_topn_exprval(ctx, 1, &prop_ref)) {
1009 FIXME("invalid ref: %08lx\n", prop_ref.u.hres);
1010 return E_FAIL;
1013 if(is_object_instance(stack_topn(ctx, 3)))
1014 obj = get_object(stack_topn(ctx, 3));
1016 if(obj) {
1017 hres = IDispatch_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
1018 if(SUCCEEDED(hres)) {
1019 hres = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, id, &id);
1020 if(hres == S_OK)
1021 hres = IDispatchEx_GetMemberName(dispex, id, &name);
1022 IDispatchEx_Release(dispex);
1023 if(FAILED(hres))
1024 return hres;
1025 }else {
1026 TRACE("No IDispatchEx\n");
1030 if(name) {
1031 jsstr_t *str;
1033 str = jsstr_alloc_len(name, SysStringLen(name));
1034 SysFreeString(name);
1035 if(!str)
1036 return E_OUTOFMEMORY;
1038 stack_pop(ctx);
1039 stack_push(ctx, jsval_number(id)); /* safe, just after pop() */
1041 hres = exprval_propput(ctx, &prop_ref, jsval_string(str));
1042 jsstr_release(str);
1043 if(FAILED(hres))
1044 return hres;
1046 jmp_next(ctx);
1047 }else {
1048 stack_popn(ctx, 4);
1049 jmp_abs(ctx, arg);
1051 return S_OK;
1054 static HRESULT scope_init_locals(script_ctx_t *ctx)
1056 call_frame_t *frame = ctx->call_ctx;
1057 unsigned int i, off, index;
1058 scope_chain_t *scope;
1059 BOOL detached_vars;
1060 jsdisp_t *jsobj;
1061 HRESULT hres;
1063 scope = frame->scope;
1064 index = scope->scope_index;
1065 detached_vars = !(frame->base_scope && frame->base_scope->frame);
1067 if (!detached_vars)
1069 assert(frame->base_scope->frame == frame);
1070 frame->scope->frame = ctx->call_ctx;
1072 else if (!scope->obj)
1074 if (FAILED(hres = create_object(ctx, NULL, &jsobj)))
1075 return hres;
1076 scope->obj = to_disp(jsobj);
1078 else
1079 jsobj = as_jsdisp(scope->obj);
1081 for(i = 0; i < frame->function->local_scopes[index].locals_cnt; i++)
1083 WCHAR *name = frame->function->local_scopes[index].locals[i].name;
1084 int ref = frame->function->local_scopes[index].locals[i].ref;
1085 jsdisp_t *func_obj;
1086 jsval_t val;
1088 if (frame->function->variables[ref].func_id != -1)
1090 TRACE("function %s %d\n", debugstr_w(name), i);
1092 if (FAILED(hres = create_source_function(ctx, frame->bytecode, frame->function->funcs
1093 + frame->function->variables[ref].func_id, ctx->call_ctx->scope, &func_obj)))
1094 return hres;
1095 val = jsval_obj(func_obj);
1096 if (detached_vars && FAILED(hres = jsdisp_propput_name(frame->variable_obj, name, jsval_obj(func_obj))))
1098 jsdisp_release(func_obj);
1099 return hres;
1102 else
1104 val = jsval_undefined();
1107 if (detached_vars)
1109 hres = jsdisp_propput_name(jsobj, name, val);
1110 jsval_release(val);
1111 if (FAILED(hres))
1112 return hres;
1114 else
1116 off = local_off(frame, ref);
1117 jsval_release(ctx->stack[off]);
1118 ctx->stack[off] = val;
1121 return S_OK;
1124 /* ECMA-262 3rd Edition 12.10 */
1125 static HRESULT interp_push_with_scope(script_ctx_t *ctx)
1127 IDispatch *disp;
1128 jsval_t v;
1129 HRESULT hres;
1131 TRACE("\n");
1133 v = stack_pop(ctx);
1134 hres = to_object(ctx, v, &disp);
1135 jsval_release(v);
1136 if(FAILED(hres))
1137 return hres;
1139 hres = scope_push(ctx, ctx->call_ctx->scope, disp, &ctx->call_ctx->scope);
1140 IDispatch_Release(disp);
1141 return hres;
1144 /* ECMA-262 10th Edition 13.3.1 */
1145 static HRESULT interp_push_block_scope(script_ctx_t *ctx)
1147 unsigned int scope_index = get_op_uint(ctx, 0);
1148 call_frame_t *frame = ctx->call_ctx;
1149 HRESULT hres;
1151 TRACE("scope_index %u.\n", scope_index);
1153 hres = scope_push(ctx, ctx->call_ctx->scope, NULL, &frame->scope);
1155 if (FAILED(hres) || !scope_index)
1156 return hres;
1158 frame->scope->scope_index = scope_index;
1160 return scope_init_locals(ctx);
1163 /* ECMA-262 3rd Edition 12.10 */
1164 static HRESULT interp_pop_scope(script_ctx_t *ctx)
1166 TRACE("\n");
1168 if(ctx->call_ctx->scope->dispex.ref > 1) {
1169 HRESULT hres = detach_variable_object(ctx, ctx->call_ctx, FALSE);
1170 if(FAILED(hres))
1171 ERR("Failed to detach variable object: %08lx\n", hres);
1174 scope_pop(&ctx->call_ctx->scope);
1175 return S_OK;
1178 /* ECMA-262 3rd Edition 12.13 */
1179 static HRESULT interp_case(script_ctx_t *ctx)
1181 const unsigned arg = get_op_uint(ctx, 0);
1182 jsval_t v;
1183 BOOL b;
1184 HRESULT hres;
1186 TRACE("\n");
1188 v = stack_pop(ctx);
1189 hres = jsval_strict_equal(stack_top(ctx), v, &b);
1190 jsval_release(v);
1191 if(FAILED(hres))
1192 return hres;
1194 if(b) {
1195 stack_popn(ctx, 1);
1196 jmp_abs(ctx, arg);
1197 }else {
1198 jmp_next(ctx);
1200 return S_OK;
1203 static void set_error_value(script_ctx_t *ctx, jsval_t value)
1205 jsexcept_t *ei = ctx->ei;
1206 jsdisp_t *obj;
1208 reset_ei(ei);
1209 ei->error = JS_E_EXCEPTION_THROWN;
1210 ei->valid_value = TRUE;
1211 ei->value = value;
1213 if(is_object_instance(value) && (obj = to_jsdisp(get_object(value)))) {
1214 UINT32 number;
1215 jsstr_t *str;
1216 jsval_t v;
1217 HRESULT hres;
1219 /* FIXME: We should check if object is an error instance */
1221 hres = jsdisp_propget_name(obj, L"number", &v);
1222 if(SUCCEEDED(hres)) {
1223 hres = to_uint32(ctx, v, &number);
1224 if(SUCCEEDED(hres))
1225 ei->error = FAILED(number) ? number : E_FAIL;
1226 jsval_release(v);
1229 hres = jsdisp_propget_name(obj, L"description", &v);
1230 if(SUCCEEDED(hres)) {
1231 hres = to_string(ctx, v, &str);
1232 if(SUCCEEDED(hres))
1233 ei->message = str;
1234 jsval_release(v);
1239 /* ECMA-262 3rd Edition 12.13 */
1240 static HRESULT interp_throw(script_ctx_t *ctx)
1242 TRACE("\n");
1244 set_error_value(ctx, stack_pop(ctx));
1245 return DISP_E_EXCEPTION;
1248 static HRESULT interp_throw_ref(script_ctx_t *ctx)
1250 const HRESULT arg = get_op_uint(ctx, 0);
1252 TRACE("%08lx\n", arg);
1254 return arg;
1257 static HRESULT interp_throw_type(script_ctx_t *ctx)
1259 const HRESULT hres = get_op_uint(ctx, 0);
1260 jsstr_t *str = get_op_str(ctx, 1);
1261 const WCHAR *ptr;
1263 TRACE("%08lx %s\n", hres, debugstr_jsstr(str));
1265 ptr = jsstr_flatten(str);
1266 return ptr ? throw_error(ctx, hres, ptr) : E_OUTOFMEMORY;
1269 /* ECMA-262 3rd Edition 12.14 */
1270 static HRESULT interp_push_except(script_ctx_t *ctx)
1272 const unsigned catch_off = get_op_uint(ctx, 0);
1273 const unsigned finally_off = get_op_uint(ctx, 1);
1274 call_frame_t *frame = ctx->call_ctx;
1275 except_frame_t *except;
1277 TRACE("\n");
1279 except = malloc(sizeof(*except));
1280 if(!except)
1281 return E_OUTOFMEMORY;
1283 except->stack_top = ctx->stack_top;
1284 except->scope = frame->scope;
1285 except->catch_off = catch_off;
1286 except->finally_off = finally_off;
1287 except->next = frame->except_frame;
1288 frame->except_frame = except;
1289 return S_OK;
1292 /* ECMA-262 3rd Edition 12.14 */
1293 static HRESULT interp_pop_except(script_ctx_t *ctx)
1295 const unsigned ret_off = get_op_uint(ctx, 0);
1296 call_frame_t *frame = ctx->call_ctx;
1297 except_frame_t *except;
1298 unsigned finally_off;
1300 TRACE("%u\n", ret_off);
1302 except = frame->except_frame;
1303 assert(except != NULL);
1305 finally_off = except->finally_off;
1306 frame->except_frame = except->next;
1307 free(except);
1309 if(finally_off) {
1310 HRESULT hres;
1312 hres = stack_push(ctx, jsval_number(ret_off));
1313 if(FAILED(hres))
1314 return hres;
1315 hres = stack_push(ctx, jsval_bool(TRUE));
1316 if(FAILED(hres))
1317 return hres;
1318 frame->ip = finally_off;
1319 }else {
1320 frame->ip = ret_off;
1323 return S_OK;
1326 /* ECMA-262 3rd Edition 12.14 */
1327 static HRESULT interp_end_finally(script_ctx_t *ctx)
1329 call_frame_t *frame = ctx->call_ctx;
1330 jsval_t v;
1332 TRACE("\n");
1334 v = stack_pop(ctx);
1335 assert(is_bool(v));
1337 if(!get_bool(v)) {
1338 TRACE("passing exception\n");
1340 set_error_value(ctx, stack_pop(ctx));
1341 return DISP_E_EXCEPTION;
1344 v = stack_pop(ctx);
1345 assert(is_number(v));
1346 frame->ip = get_number(v);
1347 return S_OK;
1350 static HRESULT interp_enter_catch(script_ctx_t *ctx)
1352 const BSTR ident = get_op_bstr(ctx, 0);
1353 jsdisp_t *scope_obj;
1354 jsval_t v;
1355 HRESULT hres;
1357 hres = create_dispex(ctx, NULL, NULL, &scope_obj);
1358 if(FAILED(hres))
1359 return hres;
1361 v = stack_pop(ctx);
1362 hres = jsdisp_propput_name(scope_obj, ident, v);
1363 jsval_release(v);
1364 if(SUCCEEDED(hres))
1365 hres = scope_push(ctx, ctx->call_ctx->scope, to_disp(scope_obj), &ctx->call_ctx->scope);
1366 jsdisp_release(scope_obj);
1367 return hres;
1370 /* ECMA-262 3rd Edition 13 */
1371 static HRESULT interp_func(script_ctx_t *ctx)
1373 unsigned func_idx = get_op_uint(ctx, 0);
1374 call_frame_t *frame = ctx->call_ctx;
1375 jsdisp_t *dispex;
1376 HRESULT hres;
1378 TRACE("%d\n", func_idx);
1380 hres = create_source_function(ctx, frame->bytecode, frame->function->funcs+func_idx,
1381 frame->scope, &dispex);
1382 if(FAILED(hres))
1383 return hres;
1385 return stack_push(ctx, jsval_obj(dispex));
1388 /* ECMA-262 3rd Edition 11.2.1 */
1389 static HRESULT interp_array(script_ctx_t *ctx)
1391 jsstr_t *name_str;
1392 const WCHAR *name;
1393 jsval_t v, namev;
1394 IDispatch *obj;
1395 DISPID id;
1396 HRESULT hres;
1398 TRACE("\n");
1400 namev = stack_pop(ctx);
1402 hres = stack_pop_object(ctx, &obj);
1403 if(FAILED(hres)) {
1404 jsval_release(namev);
1405 return hres;
1408 hres = to_flat_string(ctx, namev, &name_str, &name);
1409 jsval_release(namev);
1410 if(FAILED(hres)) {
1411 IDispatch_Release(obj);
1412 return hres;
1415 hres = disp_get_id(ctx, obj, name, NULL, 0, &id);
1416 jsstr_release(name_str);
1417 if(SUCCEEDED(hres)) {
1418 hres = disp_propget(ctx, obj, id, &v);
1419 }else if(hres == DISP_E_UNKNOWNNAME) {
1420 v = jsval_undefined();
1421 hres = S_OK;
1423 IDispatch_Release(obj);
1424 if(FAILED(hres))
1425 return hres;
1427 return stack_push(ctx, v);
1430 /* ECMA-262 3rd Edition 11.2.1 */
1431 static HRESULT interp_member(script_ctx_t *ctx)
1433 const BSTR arg = get_op_bstr(ctx, 0);
1434 IDispatch *obj;
1435 jsval_t v;
1436 DISPID id;
1437 HRESULT hres;
1439 TRACE("\n");
1441 hres = stack_pop_object(ctx, &obj);
1442 if(FAILED(hres))
1443 return hres;
1445 hres = disp_get_id(ctx, obj, arg, arg, 0, &id);
1446 if(SUCCEEDED(hres)) {
1447 hres = disp_propget(ctx, obj, id, &v);
1448 }else if(hres == DISP_E_UNKNOWNNAME) {
1449 v = jsval_undefined();
1450 hres = S_OK;
1452 IDispatch_Release(obj);
1453 if(FAILED(hres))
1454 return hres;
1456 return stack_push(ctx, v);
1459 /* ECMA-262 3rd Edition 11.2.1 */
1460 static HRESULT interp_memberid(script_ctx_t *ctx)
1462 const unsigned arg = get_op_uint(ctx, 0);
1463 jsval_t objv, namev;
1464 const WCHAR *name;
1465 jsstr_t *name_str;
1466 IDispatch *obj;
1467 exprval_t ref;
1468 DISPID id;
1469 HRESULT hres;
1471 TRACE("%x\n", arg);
1473 namev = stack_pop(ctx);
1474 objv = stack_pop(ctx);
1476 hres = to_object(ctx, objv, &obj);
1477 jsval_release(objv);
1478 if(SUCCEEDED(hres)) {
1479 hres = to_flat_string(ctx, namev, &name_str, &name);
1480 if(FAILED(hres))
1481 IDispatch_Release(obj);
1483 jsval_release(namev);
1484 if(FAILED(hres))
1485 return hres;
1487 hres = disp_get_id(ctx, obj, name, NULL, arg, &id);
1488 jsstr_release(name_str);
1489 if(SUCCEEDED(hres)) {
1490 ref.type = EXPRVAL_IDREF;
1491 ref.u.idref.disp = obj;
1492 ref.u.idref.id = id;
1493 }else {
1494 IDispatch_Release(obj);
1495 if(hres == DISP_E_UNKNOWNNAME && !(arg & fdexNameEnsure)) {
1496 exprval_set_exception(&ref, JS_E_INVALID_PROPERTY);
1497 hres = S_OK;
1498 }else {
1499 ERR("failed %08lx\n", hres);
1500 return hres;
1504 return stack_push_exprval(ctx, &ref);
1507 /* ECMA-262 3rd Edition 11.2.1 */
1508 static HRESULT interp_refval(script_ctx_t *ctx)
1510 exprval_t ref;
1511 jsval_t v;
1512 HRESULT hres;
1514 TRACE("\n");
1516 if(!stack_topn_exprval(ctx, 0, &ref))
1517 return JS_E_ILLEGAL_ASSIGN;
1519 hres = exprval_propget(ctx, &ref, &v);
1520 if(FAILED(hres))
1521 return hres;
1523 return stack_push(ctx, v);
1526 /* ECMA-262 3rd Edition 11.2.2 */
1527 static HRESULT interp_new(script_ctx_t *ctx)
1529 const unsigned argc = get_op_uint(ctx, 0);
1530 jsval_t constr;
1532 TRACE("%d\n", argc);
1534 constr = stack_topn(ctx, argc);
1536 /* NOTE: Should use to_object here */
1538 if(is_null(constr))
1539 return is_null_disp(constr) ? JS_E_INVALID_PROPERTY : JS_E_OBJECT_EXPECTED;
1540 if(!is_object_instance(constr))
1541 return JS_E_INVALID_ACTION;
1543 clear_acc(ctx);
1544 return disp_call_value(ctx, get_object(constr), jsval_undefined(), DISPATCH_CONSTRUCT | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
1545 argc, stack_args(ctx, argc), &ctx->acc);
1548 /* ECMA-262 3rd Edition 11.2.3 */
1549 static HRESULT interp_call(script_ctx_t *ctx)
1551 const unsigned argn = get_op_uint(ctx, 0);
1552 const int do_ret = get_op_int(ctx, 1);
1553 jsval_t obj;
1555 TRACE("%d %d\n", argn, do_ret);
1557 obj = stack_topn(ctx, argn);
1558 if(!is_object_instance(obj))
1559 return JS_E_INVALID_PROPERTY;
1561 clear_acc(ctx);
1562 return disp_call_value(ctx, get_object(obj), jsval_undefined(), DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
1563 argn, stack_args(ctx, argn), do_ret ? &ctx->acc : NULL);
1566 /* ECMA-262 3rd Edition 11.2.3 */
1567 static HRESULT interp_call_member(script_ctx_t *ctx)
1569 const unsigned argn = get_op_uint(ctx, 0);
1570 const int do_ret = get_op_int(ctx, 1);
1571 exprval_t ref;
1573 TRACE("%d %d\n", argn, do_ret);
1575 if(!stack_topn_exprval(ctx, argn, &ref))
1576 return ref.u.hres;
1578 clear_acc(ctx);
1579 return exprval_call(ctx, &ref, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
1580 argn, stack_args(ctx, argn), do_ret ? &ctx->acc : NULL);
1583 /* ECMA-262 5th Edition 15.1.2.1.1 */
1584 static HRESULT interp_call_eval(script_ctx_t *ctx)
1586 const unsigned argn = get_op_uint(ctx, 0);
1587 const int do_ret = get_op_int(ctx, 1);
1588 HRESULT hres = S_OK;
1589 exprval_t exprval;
1590 jsdisp_t *jsdisp;
1591 BSTR identifier;
1592 jsval_t v;
1594 TRACE("%d %d\n", argn, do_ret);
1596 identifier = SysAllocString(L"eval");
1597 hres = identifier_eval(ctx, identifier, &exprval);
1598 SysFreeString(identifier);
1599 if(FAILED(hres))
1600 return hres;
1602 clear_acc(ctx);
1603 hres = exprval_propget(ctx, &exprval, &v);
1604 if(SUCCEEDED(hres)) {
1605 if(is_object_instance(v) && (jsdisp = to_jsdisp(get_object(v))) && jsdisp->ctx == ctx && is_builtin_eval_func(jsdisp))
1606 hres = builtin_eval(ctx, ctx->call_ctx, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
1607 argn, stack_args(ctx, argn), do_ret ? &ctx->acc : NULL);
1608 else
1609 hres = exprval_call(ctx, &exprval, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
1610 argn, stack_args(ctx, argn), do_ret ? &ctx->acc : NULL);
1611 jsval_release(v);
1613 exprval_release(&exprval);
1614 return hres;
1617 /* ECMA-262 3rd Edition 11.1.1 */
1618 static HRESULT interp_this(script_ctx_t *ctx)
1620 IDispatch *this_obj = ctx->call_ctx->this_obj;
1622 TRACE("\n");
1624 if(!this_obj) {
1625 named_item_t *item = ctx->call_ctx->bytecode->named_item;
1627 if(item)
1628 this_obj = (item->flags & SCRIPTITEM_CODEONLY) ? to_disp(item->script_obj) : item->disp;
1629 else
1630 this_obj = lookup_global_host(ctx);
1633 IDispatch_AddRef(this_obj);
1634 return stack_push(ctx, jsval_disp(this_obj));
1637 static HRESULT interp_identifier_ref(script_ctx_t *ctx, BSTR identifier, unsigned flags)
1639 exprval_t exprval;
1640 HRESULT hres;
1642 hres = identifier_eval(ctx, identifier, &exprval);
1643 if(FAILED(hres))
1644 return hres;
1646 if(exprval.type == EXPRVAL_INVALID && (flags & fdexNameEnsure)) {
1647 jsdisp_t *script_obj = ctx->global;
1648 DISPID id;
1650 if(ctx->call_ctx->bytecode->named_item)
1651 script_obj = ctx->call_ctx->bytecode->named_item->script_obj;
1653 hres = jsdisp_get_id(script_obj, identifier, fdexNameEnsure, &id);
1654 if(FAILED(hres))
1655 return hres;
1657 exprval_set_disp_ref(&exprval, to_disp(script_obj), id);
1660 if(exprval.type == EXPRVAL_INVALID ||
1661 (exprval.type == EXPRVAL_JSVAL && ctx->version < SCRIPTLANGUAGEVERSION_ES5)) {
1662 WARN("invalid ref\n");
1663 exprval_release(&exprval);
1664 exprval_set_exception(&exprval, JS_E_OBJECT_EXPECTED);
1667 return stack_push_exprval(ctx, &exprval);
1670 static HRESULT identifier_value(script_ctx_t *ctx, BSTR identifier)
1672 exprval_t exprval;
1673 jsval_t v;
1674 HRESULT hres;
1676 hres = identifier_eval(ctx, identifier, &exprval);
1677 if(FAILED(hres))
1678 return hres;
1680 if(exprval.type == EXPRVAL_INVALID)
1681 return throw_error(ctx, exprval.u.hres, identifier);
1683 hres = exprval_to_value(ctx, &exprval, &v);
1684 if(FAILED(hres))
1685 return hres;
1687 return stack_push(ctx, v);
1690 static HRESULT interp_local_ref(script_ctx_t *ctx)
1692 const int arg = get_op_int(ctx, 0);
1693 const unsigned flags = get_op_uint(ctx, 1);
1694 call_frame_t *frame = ctx->call_ctx;
1695 exprval_t ref;
1697 TRACE("%s\n", debugstr_w(local_name(frame, arg)));
1699 if(!frame->base_scope || !frame->base_scope->frame)
1700 return interp_identifier_ref(ctx, local_name(frame, arg), flags);
1702 ref.type = EXPRVAL_STACK_REF;
1703 ref.u.off = local_off(frame, arg);
1704 return stack_push_exprval(ctx, &ref);
1707 static HRESULT interp_local(script_ctx_t *ctx)
1709 const int arg = get_op_int(ctx, 0);
1710 call_frame_t *frame = ctx->call_ctx;
1711 jsval_t copy;
1712 HRESULT hres;
1714 if(!frame->base_scope || !frame->base_scope->frame) {
1715 TRACE("%s\n", debugstr_w(local_name(frame, arg)));
1716 return identifier_value(ctx, local_name(frame, arg));
1719 hres = jsval_copy(ctx->stack[local_off(frame, arg)], &copy);
1720 if(FAILED(hres))
1721 return hres;
1723 TRACE("%s: %s\n", debugstr_w(local_name(frame, arg)), debugstr_jsval(copy));
1724 return stack_push(ctx, copy);
1727 /* ECMA-262 3rd Edition 10.1.4 */
1728 static HRESULT interp_ident(script_ctx_t *ctx)
1730 const BSTR arg = get_op_bstr(ctx, 0);
1732 TRACE("%s\n", debugstr_w(arg));
1734 return identifier_value(ctx, arg);
1737 /* ECMA-262 3rd Edition 10.1.4 */
1738 static HRESULT interp_identid(script_ctx_t *ctx)
1740 const BSTR arg = get_op_bstr(ctx, 0);
1741 const unsigned flags = get_op_uint(ctx, 1);
1743 TRACE("%s %x\n", debugstr_w(arg), flags);
1745 return interp_identifier_ref(ctx, arg, flags);
1748 /* ECMA-262 3rd Edition 7.8.1 */
1749 static HRESULT interp_null(script_ctx_t *ctx)
1751 TRACE("\n");
1753 return stack_push(ctx, jsval_null());
1756 /* ECMA-262 3rd Edition 7.8.2 */
1757 static HRESULT interp_bool(script_ctx_t *ctx)
1759 const int arg = get_op_int(ctx, 0);
1761 TRACE("%s\n", arg ? "true" : "false");
1763 return stack_push(ctx, jsval_bool(arg));
1766 /* ECMA-262 3rd Edition 7.8.3 */
1767 static HRESULT interp_int(script_ctx_t *ctx)
1769 const int arg = get_op_int(ctx, 0);
1771 TRACE("%d\n", arg);
1773 return stack_push(ctx, jsval_number(arg));
1776 /* ECMA-262 3rd Edition 7.8.3 */
1777 static HRESULT interp_double(script_ctx_t *ctx)
1779 const double arg = get_op_double(ctx);
1781 TRACE("%lf\n", arg);
1783 return stack_push(ctx, jsval_number(arg));
1786 /* ECMA-262 3rd Edition 7.8.4 */
1787 static HRESULT interp_str(script_ctx_t *ctx)
1789 jsstr_t *str = get_op_str(ctx, 0);
1791 TRACE("%s\n", debugstr_jsstr(str));
1793 return stack_push(ctx, jsval_string(jsstr_addref(str)));
1796 /* ECMA-262 3rd Edition 7.8 */
1797 static HRESULT interp_regexp(script_ctx_t *ctx)
1799 jsstr_t *source = get_op_str(ctx, 0);
1800 const unsigned flags = get_op_uint(ctx, 1);
1801 jsdisp_t *regexp;
1802 HRESULT hres;
1804 TRACE("%s %x\n", debugstr_jsstr(source), flags);
1806 hres = create_regexp(ctx, source, flags, &regexp);
1807 if(FAILED(hres))
1808 return hres;
1810 return stack_push(ctx, jsval_obj(regexp));
1813 /* ECMA-262 3rd Edition 11.1.4 */
1814 static HRESULT interp_carray(script_ctx_t *ctx)
1816 const unsigned arg = get_op_uint(ctx, 0);
1817 jsdisp_t *array;
1818 HRESULT hres;
1820 TRACE("%u\n", arg);
1822 hres = create_array(ctx, arg, &array);
1823 if(FAILED(hres))
1824 return hres;
1826 return stack_push(ctx, jsval_obj(array));
1829 static HRESULT interp_carray_set(script_ctx_t *ctx)
1831 const unsigned index = get_op_uint(ctx, 0);
1832 jsval_t value, array;
1833 HRESULT hres;
1835 value = stack_pop(ctx);
1837 TRACE("[%u] = %s\n", index, debugstr_jsval(value));
1839 array = stack_top(ctx);
1840 assert(is_object_instance(array));
1842 hres = jsdisp_propput_idx(to_jsdisp(get_object(array)), index, value);
1843 jsval_release(value);
1844 return hres;
1847 /* ECMA-262 3rd Edition 11.1.5 */
1848 static HRESULT interp_new_obj(script_ctx_t *ctx)
1850 jsdisp_t *obj;
1851 HRESULT hres;
1853 TRACE("\n");
1855 hres = create_object(ctx, NULL, &obj);
1856 if(FAILED(hres))
1857 return hres;
1859 return stack_push(ctx, jsval_obj(obj));
1862 /* ECMA-262 3rd Edition 11.1.5 */
1863 static HRESULT interp_obj_prop(script_ctx_t *ctx)
1865 jsstr_t *name_arg = get_op_str(ctx, 0);
1866 unsigned type = get_op_uint(ctx, 1);
1867 const WCHAR *name;
1868 jsdisp_t *obj;
1869 jsval_t val;
1870 HRESULT hres;
1872 TRACE("%s\n", debugstr_jsstr(name_arg));
1874 val = stack_pop(ctx);
1876 /* FIXME: we should pass it as jsstr_t */
1877 name = jsstr_flatten(name_arg);
1879 assert(is_object_instance(stack_top(ctx)));
1880 obj = as_jsdisp(get_object(stack_top(ctx)));
1882 if(type == PROPERTY_DEFINITION_VALUE) {
1883 hres = jsdisp_propput_name(obj, name, val);
1884 }else {
1885 property_desc_t desc = {PROPF_ENUMERABLE | PROPF_CONFIGURABLE};
1886 jsdisp_t *func;
1888 assert(is_object_instance(val));
1889 func = to_jsdisp(get_object(val));
1891 desc.mask = desc.flags;
1892 if(type == PROPERTY_DEFINITION_GETTER) {
1893 desc.explicit_getter = TRUE;
1894 desc.getter = func;
1895 }else {
1896 desc.explicit_setter = TRUE;
1897 desc.setter = func;
1900 hres = jsdisp_define_property(obj, name, &desc);
1903 jsval_release(val);
1904 return hres;
1907 /* ECMA-262 3rd Edition 11.11 */
1908 static HRESULT interp_cnd_nz(script_ctx_t *ctx)
1910 const unsigned arg = get_op_uint(ctx, 0);
1911 BOOL b;
1912 HRESULT hres;
1914 TRACE("\n");
1916 hres = to_boolean(stack_top(ctx), &b);
1917 if(FAILED(hres))
1918 return hres;
1920 if(b) {
1921 jmp_abs(ctx, arg);
1922 }else {
1923 stack_popn(ctx, 1);
1924 jmp_next(ctx);
1926 return S_OK;
1929 /* ECMA-262 3rd Edition 11.11 */
1930 static HRESULT interp_cnd_z(script_ctx_t *ctx)
1932 const unsigned arg = get_op_uint(ctx, 0);
1933 BOOL b;
1934 HRESULT hres;
1936 TRACE("\n");
1938 hres = to_boolean(stack_top(ctx), &b);
1939 if(FAILED(hres))
1940 return hres;
1942 if(b) {
1943 stack_popn(ctx, 1);
1944 jmp_next(ctx);
1945 }else {
1946 jmp_abs(ctx, arg);
1948 return S_OK;
1951 /* ECMA-262 3rd Edition 11.10 */
1952 static HRESULT interp_or(script_ctx_t *ctx)
1954 INT l, r;
1955 HRESULT hres;
1957 TRACE("\n");
1959 hres = stack_pop_int(ctx, &r);
1960 if(FAILED(hres))
1961 return hres;
1963 hres = stack_pop_int(ctx, &l);
1964 if(FAILED(hres))
1965 return hres;
1967 return stack_push(ctx, jsval_number(l|r));
1970 /* ECMA-262 3rd Edition 11.10 */
1971 static HRESULT interp_xor(script_ctx_t *ctx)
1973 INT l, r;
1974 HRESULT hres;
1976 TRACE("\n");
1978 hres = stack_pop_int(ctx, &r);
1979 if(FAILED(hres))
1980 return hres;
1982 hres = stack_pop_int(ctx, &l);
1983 if(FAILED(hres))
1984 return hres;
1986 return stack_push(ctx, jsval_number(l^r));
1989 /* ECMA-262 3rd Edition 11.10 */
1990 static HRESULT interp_and(script_ctx_t *ctx)
1992 INT l, r;
1993 HRESULT hres;
1995 TRACE("\n");
1997 hres = stack_pop_int(ctx, &r);
1998 if(FAILED(hres))
1999 return hres;
2001 hres = stack_pop_int(ctx, &l);
2002 if(FAILED(hres))
2003 return hres;
2005 return stack_push(ctx, jsval_number(l&r));
2008 /* ECMA-262 3rd Edition 11.8.6 */
2009 static HRESULT interp_instanceof(script_ctx_t *ctx)
2011 jsdisp_t *obj, *iter, *tmp = NULL;
2012 jsval_t prot, v;
2013 BOOL ret = FALSE;
2014 HRESULT hres;
2016 v = stack_pop(ctx);
2017 if(!is_object_instance(v)) {
2018 jsval_release(v);
2019 return JS_E_FUNCTION_EXPECTED;
2022 obj = iface_to_jsdisp(get_object(v));
2023 IDispatch_Release(get_object(v));
2024 if(!obj) {
2025 FIXME("non-jsdisp objects not supported\n");
2026 return E_FAIL;
2029 if(is_class(obj, JSCLASS_FUNCTION)) {
2030 hres = jsdisp_propget_name(obj, L"prototype", &prot);
2031 }else {
2032 hres = JS_E_FUNCTION_EXPECTED;
2034 jsdisp_release(obj);
2035 if(FAILED(hres))
2036 return hres;
2038 v = stack_pop(ctx);
2040 if(is_null_disp(v))
2041 hres = JS_E_OBJECT_EXPECTED;
2042 else if(is_object_instance(prot)) {
2043 if(is_object_instance(v))
2044 tmp = to_jsdisp(get_object(v));
2045 for(iter = tmp; !ret && iter; iter = iter->prototype) {
2046 hres = disp_cmp(get_object(prot), to_disp(iter), &ret);
2047 if(FAILED(hres))
2048 break;
2050 }else {
2051 FIXME("prototype is not an object\n");
2052 hres = E_FAIL;
2055 jsval_release(prot);
2056 jsval_release(v);
2057 if(FAILED(hres))
2058 return hres;
2060 return stack_push(ctx, jsval_bool(ret));
2063 /* ECMA-262 3rd Edition 11.8.7 */
2064 static HRESULT interp_in(script_ctx_t *ctx)
2066 const WCHAR *str;
2067 jsstr_t *jsstr;
2068 jsval_t obj, v;
2069 DISPID id = 0;
2070 BOOL ret;
2071 HRESULT hres;
2073 TRACE("\n");
2075 obj = stack_pop(ctx);
2076 if(!is_object_instance(obj)) {
2077 jsval_release(obj);
2078 return JS_E_OBJECT_EXPECTED;
2081 v = stack_pop(ctx);
2082 hres = to_flat_string(ctx, v, &jsstr, &str);
2083 jsval_release(v);
2084 if(FAILED(hres)) {
2085 IDispatch_Release(get_object(obj));
2086 return hres;
2089 hres = disp_get_id(ctx, get_object(obj), str, NULL, 0, &id);
2090 IDispatch_Release(get_object(obj));
2091 jsstr_release(jsstr);
2092 if(SUCCEEDED(hres))
2093 ret = TRUE;
2094 else if(hres == DISP_E_UNKNOWNNAME)
2095 ret = FALSE;
2096 else
2097 return hres;
2099 return stack_push(ctx, jsval_bool(ret));
2102 /* ECMA-262 3rd Edition 11.6.1 */
2103 static HRESULT interp_add(script_ctx_t *ctx)
2105 jsval_t l, r, lval, rval, ret;
2106 HRESULT hres;
2108 rval = stack_pop(ctx);
2109 lval = stack_pop(ctx);
2111 TRACE("%s + %s\n", debugstr_jsval(lval), debugstr_jsval(rval));
2113 hres = to_primitive(ctx, lval, &l, NO_HINT);
2114 if(SUCCEEDED(hres)) {
2115 hres = to_primitive(ctx, rval, &r, NO_HINT);
2116 if(FAILED(hres))
2117 jsval_release(l);
2119 jsval_release(lval);
2120 jsval_release(rval);
2121 if(FAILED(hres))
2122 return hres;
2124 if(is_string(l) || is_string(r)) {
2125 jsstr_t *lstr, *rstr = NULL;
2127 hres = to_string(ctx, l, &lstr);
2128 if(SUCCEEDED(hres))
2129 hres = to_string(ctx, r, &rstr);
2131 if(SUCCEEDED(hres)) {
2132 jsstr_t *ret_str;
2134 ret_str = jsstr_concat(lstr, rstr);
2135 if(ret_str)
2136 ret = jsval_string(ret_str);
2137 else
2138 hres = E_OUTOFMEMORY;
2141 jsstr_release(lstr);
2142 if(rstr)
2143 jsstr_release(rstr);
2144 }else {
2145 double nl, nr;
2147 hres = to_number(ctx, l, &nl);
2148 if(SUCCEEDED(hres)) {
2149 hres = to_number(ctx, r, &nr);
2150 if(SUCCEEDED(hres))
2151 ret = jsval_number(nl+nr);
2155 jsval_release(r);
2156 jsval_release(l);
2157 if(FAILED(hres))
2158 return hres;
2160 return stack_push(ctx, ret);
2163 /* ECMA-262 3rd Edition 11.6.2 */
2164 static HRESULT interp_sub(script_ctx_t *ctx)
2166 double l, r;
2167 HRESULT hres;
2169 TRACE("\n");
2171 hres = stack_pop_number(ctx, &r);
2172 if(FAILED(hres))
2173 return hres;
2175 hres = stack_pop_number(ctx, &l);
2176 if(FAILED(hres))
2177 return hres;
2179 return stack_push(ctx, jsval_number(l-r));
2182 /* ECMA-262 3rd Edition 11.5.1 */
2183 static HRESULT interp_mul(script_ctx_t *ctx)
2185 double l, r;
2186 HRESULT hres;
2188 TRACE("\n");
2190 hres = stack_pop_number(ctx, &r);
2191 if(FAILED(hres))
2192 return hres;
2194 hres = stack_pop_number(ctx, &l);
2195 if(FAILED(hres))
2196 return hres;
2198 return stack_push(ctx, jsval_number(l*r));
2201 /* ECMA-262 3rd Edition 11.5.2 */
2202 static HRESULT interp_div(script_ctx_t *ctx)
2204 double l, r;
2205 HRESULT hres;
2207 TRACE("\n");
2209 hres = stack_pop_number(ctx, &r);
2210 if(FAILED(hres))
2211 return hres;
2213 hres = stack_pop_number(ctx, &l);
2214 if(FAILED(hres))
2215 return hres;
2217 return stack_push(ctx, jsval_number(l/r));
2220 /* ECMA-262 3rd Edition 11.5.3 */
2221 static HRESULT interp_mod(script_ctx_t *ctx)
2223 double l, r;
2224 HRESULT hres;
2226 TRACE("\n");
2228 hres = stack_pop_number(ctx, &r);
2229 if(FAILED(hres))
2230 return hres;
2232 hres = stack_pop_number(ctx, &l);
2233 if(FAILED(hres))
2234 return hres;
2236 return stack_push(ctx, jsval_number(fmod(l, r)));
2239 /* ECMA-262 3rd Edition 11.4.2 */
2240 static HRESULT interp_delete(script_ctx_t *ctx)
2242 jsval_t objv, namev;
2243 IDispatch *obj;
2244 jsstr_t *name;
2245 BOOL ret;
2246 HRESULT hres;
2248 TRACE("\n");
2250 namev = stack_pop(ctx);
2251 objv = stack_pop(ctx);
2253 hres = to_object(ctx, objv, &obj);
2254 jsval_release(objv);
2255 if(FAILED(hres)) {
2256 jsval_release(namev);
2257 return hres;
2260 hres = to_string(ctx, namev, &name);
2261 jsval_release(namev);
2262 if(FAILED(hres)) {
2263 IDispatch_Release(obj);
2264 return hres;
2267 hres = disp_delete_name(ctx, obj, name, &ret);
2268 IDispatch_Release(obj);
2269 jsstr_release(name);
2270 if(FAILED(hres))
2271 return hres;
2273 return stack_push(ctx, jsval_bool(ret));
2276 /* ECMA-262 3rd Edition 11.4.2 */
2277 static HRESULT interp_delete_ident(script_ctx_t *ctx)
2279 const BSTR arg = get_op_bstr(ctx, 0);
2280 exprval_t exprval;
2281 BOOL ret;
2282 HRESULT hres;
2284 TRACE("%s\n", debugstr_w(arg));
2286 hres = identifier_eval(ctx, arg, &exprval);
2287 if(FAILED(hres))
2288 return hres;
2290 switch(exprval.type) {
2291 case EXPRVAL_STACK_REF:
2292 ret = FALSE;
2293 break;
2294 case EXPRVAL_IDREF:
2295 hres = disp_delete(exprval.u.idref.disp, exprval.u.idref.id, &ret);
2296 IDispatch_Release(exprval.u.idref.disp);
2297 if(FAILED(hres))
2298 return hres;
2299 break;
2300 case EXPRVAL_INVALID:
2301 ret = TRUE;
2302 break;
2303 default:
2304 FIXME("Unsupported exprval\n");
2305 exprval_release(&exprval);
2306 return E_NOTIMPL;
2310 return stack_push(ctx, jsval_bool(ret));
2313 /* ECMA-262 3rd Edition 11.4.2 */
2314 static HRESULT interp_void(script_ctx_t *ctx)
2316 TRACE("\n");
2318 stack_popn(ctx, 1);
2319 return stack_push(ctx, jsval_undefined());
2322 /* ECMA-262 3rd Edition 11.4.3 */
2323 static HRESULT typeof_string(jsval_t v, const WCHAR **ret)
2325 switch(jsval_type(v)) {
2326 case JSV_UNDEFINED:
2327 *ret = L"undefined";
2328 break;
2329 case JSV_NULL:
2330 *ret = L"object";
2331 break;
2332 case JSV_OBJECT: {
2333 jsdisp_t *dispex;
2335 if((dispex = to_jsdisp(get_object(v)))) {
2336 *ret = is_class(dispex, JSCLASS_FUNCTION) ? L"function" : L"object";
2337 }else {
2338 *ret = L"object";
2340 break;
2342 case JSV_STRING:
2343 *ret = L"string";
2344 break;
2345 case JSV_NUMBER:
2346 *ret = L"number";
2347 break;
2348 case JSV_BOOL:
2349 *ret = L"boolean";
2350 break;
2351 case JSV_VARIANT:
2352 FIXME("unhandled variant %s\n", debugstr_variant(get_variant(v)));
2353 return E_NOTIMPL;
2356 return S_OK;
2359 /* ECMA-262 3rd Edition 11.4.3 */
2360 static HRESULT interp_typeofid(script_ctx_t *ctx)
2362 const WCHAR *ret;
2363 exprval_t ref;
2364 jsval_t v;
2365 HRESULT hres;
2367 TRACE("\n");
2369 if(!stack_pop_exprval(ctx, &ref))
2370 return stack_push(ctx, jsval_string(jsstr_undefined()));
2372 hres = exprval_propget(ctx, &ref, &v);
2373 exprval_release(&ref);
2374 if(FAILED(hres))
2375 return stack_push_string(ctx, L"unknown");
2377 hres = typeof_string(v, &ret);
2378 jsval_release(v);
2379 if(FAILED(hres))
2380 return hres;
2382 return stack_push_string(ctx, ret);
2385 /* ECMA-262 3rd Edition 11.4.3 */
2386 static HRESULT interp_typeofident(script_ctx_t *ctx)
2388 const BSTR arg = get_op_bstr(ctx, 0);
2389 exprval_t exprval;
2390 const WCHAR *ret;
2391 jsval_t v;
2392 HRESULT hres;
2394 TRACE("%s\n", debugstr_w(arg));
2396 hres = identifier_eval(ctx, arg, &exprval);
2397 if(FAILED(hres))
2398 return hres;
2400 if(exprval.type == EXPRVAL_INVALID)
2401 return stack_push(ctx, jsval_string(jsstr_undefined()));
2403 hres = exprval_to_value(ctx, &exprval, &v);
2404 if(FAILED(hres))
2405 return hres;
2407 hres = typeof_string(v, &ret);
2408 jsval_release(v);
2409 if(FAILED(hres))
2410 return hres;
2412 return stack_push_string(ctx, ret);
2415 /* ECMA-262 3rd Edition 11.4.3 */
2416 static HRESULT interp_typeof(script_ctx_t *ctx)
2418 const WCHAR *ret;
2419 jsval_t v;
2420 HRESULT hres;
2422 TRACE("\n");
2424 v = stack_pop(ctx);
2425 hres = typeof_string(v, &ret);
2426 jsval_release(v);
2427 if(FAILED(hres))
2428 return hres;
2430 return stack_push_string(ctx, ret);
2433 /* ECMA-262 3rd Edition 11.4.7 */
2434 static HRESULT interp_minus(script_ctx_t *ctx)
2436 double n;
2437 HRESULT hres;
2439 TRACE("\n");
2441 hres = stack_pop_number(ctx, &n);
2442 if(FAILED(hres))
2443 return hres;
2445 return stack_push(ctx, jsval_number(-n));
2448 /* ECMA-262 3rd Edition 11.4.6 */
2449 static HRESULT interp_tonum(script_ctx_t *ctx)
2451 jsval_t v;
2452 double n;
2453 HRESULT hres;
2455 TRACE("\n");
2457 v = stack_pop(ctx);
2458 hres = to_number(ctx, v, &n);
2459 jsval_release(v);
2460 if(FAILED(hres))
2461 return hres;
2463 return stack_push(ctx, jsval_number(n));
2466 /* ECMA-262 3rd Edition 11.3.1 */
2467 static HRESULT interp_postinc(script_ctx_t *ctx)
2469 const int arg = get_op_int(ctx, 0);
2470 exprval_t ref;
2471 jsval_t v;
2472 HRESULT hres;
2474 TRACE("%d\n", arg);
2476 if(!stack_pop_exprval(ctx, &ref))
2477 return JS_E_OBJECT_EXPECTED;
2479 hres = exprval_propget(ctx, &ref, &v);
2480 if(SUCCEEDED(hres)) {
2481 double n;
2483 hres = to_number(ctx, v, &n);
2484 if(SUCCEEDED(hres))
2485 hres = exprval_propput(ctx, &ref, jsval_number(n+(double)arg));
2486 if(FAILED(hres))
2487 jsval_release(v);
2489 exprval_release(&ref);
2490 if(FAILED(hres))
2491 return hres;
2493 return stack_push(ctx, v);
2496 /* ECMA-262 3rd Edition 11.4.4, 11.4.5 */
2497 static HRESULT interp_preinc(script_ctx_t *ctx)
2499 const int arg = get_op_int(ctx, 0);
2500 exprval_t ref;
2501 double ret;
2502 jsval_t v;
2503 HRESULT hres;
2505 TRACE("%d\n", arg);
2507 if(!stack_pop_exprval(ctx, &ref))
2508 return JS_E_OBJECT_EXPECTED;
2510 hres = exprval_propget(ctx, &ref, &v);
2511 if(SUCCEEDED(hres)) {
2512 double n;
2514 hres = to_number(ctx, v, &n);
2515 jsval_release(v);
2516 if(SUCCEEDED(hres)) {
2517 ret = n+(double)arg;
2518 hres = exprval_propput(ctx, &ref, jsval_number(ret));
2521 exprval_release(&ref);
2522 if(FAILED(hres))
2523 return hres;
2525 return stack_push(ctx, jsval_number(ret));
2528 /* ECMA-262 3rd Edition 11.9.3 */
2529 static HRESULT equal_values(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL *ret)
2531 if(jsval_type(lval) == jsval_type(rval) || (is_number(lval) && is_number(rval)))
2532 return jsval_strict_equal(lval, rval, ret);
2534 if((is_null(lval) && is_undefined(rval)) || (is_undefined(lval) && is_null(rval))) {
2535 *ret = TRUE;
2536 return S_OK;
2539 if(is_string(lval) && is_number(rval)) {
2540 double n;
2541 HRESULT hres;
2543 hres = to_number(ctx, lval, &n);
2544 if(FAILED(hres))
2545 return hres;
2547 /* FIXME: optimize */
2548 return equal_values(ctx, jsval_number(n), rval, ret);
2551 if(is_string(rval) && is_number(lval)) {
2552 double n;
2553 HRESULT hres;
2555 hres = to_number(ctx, rval, &n);
2556 if(FAILED(hres))
2557 return hres;
2559 /* FIXME: optimize */
2560 return equal_values(ctx, lval, jsval_number(n), ret);
2563 if(is_bool(rval))
2564 return equal_values(ctx, lval, jsval_number(get_bool(rval) ? 1 : 0), ret);
2566 if(is_bool(lval))
2567 return equal_values(ctx, jsval_number(get_bool(lval) ? 1 : 0), rval, ret);
2570 if(is_object_instance(rval) && (is_string(lval) || is_number(lval))) {
2571 jsval_t prim;
2572 HRESULT hres;
2574 hres = to_primitive(ctx, rval, &prim, NO_HINT);
2575 if(FAILED(hres))
2576 return hres;
2578 hres = equal_values(ctx, lval, prim, ret);
2579 jsval_release(prim);
2580 return hres;
2584 if(is_object_instance(lval) && (is_string(rval) || is_number(rval))) {
2585 jsval_t prim;
2586 HRESULT hres;
2588 hres = to_primitive(ctx, lval, &prim, NO_HINT);
2589 if(FAILED(hres))
2590 return hres;
2592 hres = equal_values(ctx, prim, rval, ret);
2593 jsval_release(prim);
2594 return hres;
2598 *ret = FALSE;
2599 return S_OK;
2602 /* ECMA-262 3rd Edition 11.9.1 */
2603 static HRESULT interp_eq(script_ctx_t *ctx)
2605 jsval_t l, r;
2606 BOOL b;
2607 HRESULT hres;
2609 r = stack_pop(ctx);
2610 l = stack_pop(ctx);
2612 TRACE("%s == %s\n", debugstr_jsval(l), debugstr_jsval(r));
2614 hres = equal_values(ctx, l, r, &b);
2615 jsval_release(l);
2616 jsval_release(r);
2617 if(FAILED(hres))
2618 return hres;
2620 return stack_push(ctx, jsval_bool(b));
2623 /* ECMA-262 3rd Edition 11.9.2 */
2624 static HRESULT interp_neq(script_ctx_t *ctx)
2626 jsval_t l, r;
2627 BOOL b;
2628 HRESULT hres;
2630 r = stack_pop(ctx);
2631 l = stack_pop(ctx);
2633 TRACE("%s != %s\n", debugstr_jsval(l), debugstr_jsval(r));
2635 hres = equal_values(ctx, l, r, &b);
2636 jsval_release(l);
2637 jsval_release(r);
2638 if(FAILED(hres))
2639 return hres;
2641 return stack_push(ctx, jsval_bool(!b));
2644 /* ECMA-262 3rd Edition 11.9.4 */
2645 static HRESULT interp_eq2(script_ctx_t *ctx)
2647 jsval_t l, r;
2648 BOOL b;
2649 HRESULT hres;
2651 r = stack_pop(ctx);
2652 l = stack_pop(ctx);
2654 TRACE("%s === %s\n", debugstr_jsval(l), debugstr_jsval(r));
2656 hres = jsval_strict_equal(r, l, &b);
2657 jsval_release(l);
2658 jsval_release(r);
2659 if(FAILED(hres))
2660 return hres;
2662 return stack_push(ctx, jsval_bool(b));
2665 /* ECMA-262 3rd Edition 11.9.5 */
2666 static HRESULT interp_neq2(script_ctx_t *ctx)
2668 jsval_t l, r;
2669 BOOL b;
2670 HRESULT hres;
2672 TRACE("\n");
2674 r = stack_pop(ctx);
2675 l = stack_pop(ctx);
2677 hres = jsval_strict_equal(r, l, &b);
2678 jsval_release(l);
2679 jsval_release(r);
2680 if(FAILED(hres))
2681 return hres;
2683 return stack_push(ctx, jsval_bool(!b));
2686 /* ECMA-262 3rd Edition 11.8.5 */
2687 static HRESULT less_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL greater, BOOL *ret)
2689 double ln, rn;
2690 jsval_t l, r;
2691 HRESULT hres;
2693 hres = to_primitive(ctx, lval, &l, NO_HINT);
2694 if(FAILED(hres))
2695 return hres;
2697 hres = to_primitive(ctx, rval, &r, NO_HINT);
2698 if(FAILED(hres)) {
2699 jsval_release(l);
2700 return hres;
2703 if(is_string(l) && is_string(r)) {
2704 *ret = (jsstr_cmp(get_string(l), get_string(r)) < 0) ^ greater;
2705 jsstr_release(get_string(l));
2706 jsstr_release(get_string(r));
2707 return S_OK;
2710 hres = to_number(ctx, l, &ln);
2711 jsval_release(l);
2712 if(SUCCEEDED(hres))
2713 hres = to_number(ctx, r, &rn);
2714 jsval_release(r);
2715 if(FAILED(hres))
2716 return hres;
2718 *ret = !isnan(ln) && !isnan(rn) && ((ln < rn) ^ greater);
2719 return S_OK;
2722 /* ECMA-262 3rd Edition 11.8.1 */
2723 static HRESULT interp_lt(script_ctx_t *ctx)
2725 jsval_t l, r;
2726 BOOL b;
2727 HRESULT hres;
2729 r = stack_pop(ctx);
2730 l = stack_pop(ctx);
2732 TRACE("%s < %s\n", debugstr_jsval(l), debugstr_jsval(r));
2734 hres = less_eval(ctx, l, r, FALSE, &b);
2735 jsval_release(l);
2736 jsval_release(r);
2737 if(FAILED(hres))
2738 return hres;
2740 return stack_push(ctx, jsval_bool(b));
2743 /* ECMA-262 3rd Edition 11.8.1 */
2744 static HRESULT interp_lteq(script_ctx_t *ctx)
2746 jsval_t l, r;
2747 BOOL b;
2748 HRESULT hres;
2750 r = stack_pop(ctx);
2751 l = stack_pop(ctx);
2753 TRACE("%s <= %s\n", debugstr_jsval(l), debugstr_jsval(r));
2755 hres = less_eval(ctx, r, l, TRUE, &b);
2756 jsval_release(l);
2757 jsval_release(r);
2758 if(FAILED(hres))
2759 return hres;
2761 return stack_push(ctx, jsval_bool(b));
2764 /* ECMA-262 3rd Edition 11.8.2 */
2765 static HRESULT interp_gt(script_ctx_t *ctx)
2767 jsval_t l, r;
2768 BOOL b;
2769 HRESULT hres;
2771 r = stack_pop(ctx);
2772 l = stack_pop(ctx);
2774 TRACE("%s > %s\n", debugstr_jsval(l), debugstr_jsval(r));
2776 hres = less_eval(ctx, r, l, FALSE, &b);
2777 jsval_release(l);
2778 jsval_release(r);
2779 if(FAILED(hres))
2780 return hres;
2782 return stack_push(ctx, jsval_bool(b));
2785 /* ECMA-262 3rd Edition 11.8.4 */
2786 static HRESULT interp_gteq(script_ctx_t *ctx)
2788 jsval_t l, r;
2789 BOOL b;
2790 HRESULT hres;
2792 r = stack_pop(ctx);
2793 l = stack_pop(ctx);
2795 TRACE("%s >= %s\n", debugstr_jsval(l), debugstr_jsval(r));
2797 hres = less_eval(ctx, l, r, TRUE, &b);
2798 jsval_release(l);
2799 jsval_release(r);
2800 if(FAILED(hres))
2801 return hres;
2803 return stack_push(ctx, jsval_bool(b));
2806 /* ECMA-262 3rd Edition 11.4.8 */
2807 static HRESULT interp_bneg(script_ctx_t *ctx)
2809 jsval_t v;
2810 INT i;
2811 HRESULT hres;
2813 TRACE("\n");
2815 v = stack_pop(ctx);
2816 hres = to_int32(ctx, v, &i);
2817 jsval_release(v);
2818 if(FAILED(hres))
2819 return hres;
2821 return stack_push(ctx, jsval_number(~i));
2824 /* ECMA-262 3rd Edition 11.4.9 */
2825 static HRESULT interp_neg(script_ctx_t *ctx)
2827 jsval_t v;
2828 BOOL b;
2829 HRESULT hres;
2831 TRACE("\n");
2833 v = stack_pop(ctx);
2834 hres = to_boolean(v, &b);
2835 jsval_release(v);
2836 if(FAILED(hres))
2837 return hres;
2839 return stack_push(ctx, jsval_bool(!b));
2842 /* ECMA-262 3rd Edition 11.7.1 */
2843 static HRESULT interp_lshift(script_ctx_t *ctx)
2845 UINT32 r;
2846 INT l;
2847 HRESULT hres;
2849 hres = stack_pop_uint(ctx, &r);
2850 if(FAILED(hres))
2851 return hres;
2853 hres = stack_pop_int(ctx, &l);
2854 if(FAILED(hres))
2855 return hres;
2857 return stack_push(ctx, jsval_number(l << (r&0x1f)));
2860 /* ECMA-262 3rd Edition 11.7.2 */
2861 static HRESULT interp_rshift(script_ctx_t *ctx)
2863 UINT32 r;
2864 INT l;
2865 HRESULT hres;
2867 hres = stack_pop_uint(ctx, &r);
2868 if(FAILED(hres))
2869 return hres;
2871 hres = stack_pop_int(ctx, &l);
2872 if(FAILED(hres))
2873 return hres;
2875 return stack_push(ctx, jsval_number(l >> (r&0x1f)));
2878 /* ECMA-262 3rd Edition 11.7.3 */
2879 static HRESULT interp_rshift2(script_ctx_t *ctx)
2881 UINT32 r, l;
2882 HRESULT hres;
2884 hres = stack_pop_uint(ctx, &r);
2885 if(FAILED(hres))
2886 return hres;
2888 hres = stack_pop_uint(ctx, &l);
2889 if(FAILED(hres))
2890 return hres;
2892 return stack_push(ctx, jsval_number(l >> (r&0x1f)));
2895 /* ECMA-262 3rd Edition 9.8 */
2896 static HRESULT interp_to_string(script_ctx_t *ctx)
2898 jsstr_t *str;
2899 jsval_t v;
2900 HRESULT hres;
2902 v = stack_pop(ctx);
2903 TRACE("%s\n", debugstr_jsval(v));
2904 hres = to_string(ctx, v, &str);
2905 jsval_release(v);
2906 if(FAILED(hres)) {
2907 WARN("failed %08lx\n", hres);
2908 return hres;
2911 return stack_push(ctx, jsval_string(str));
2914 /* ECMA-262 3rd Edition 11.13.1 */
2915 static HRESULT interp_assign(script_ctx_t *ctx)
2917 exprval_t ref;
2918 jsval_t v;
2919 HRESULT hres;
2921 TRACE("\n");
2923 v = stack_pop(ctx);
2925 if(!stack_pop_exprval(ctx, &ref)) {
2926 jsval_release(v);
2927 return JS_E_ILLEGAL_ASSIGN;
2930 hres = exprval_propput(ctx, &ref, v);
2931 exprval_release(&ref);
2932 if(FAILED(hres)) {
2933 jsval_release(v);
2934 return hres;
2937 return stack_push(ctx, v);
2940 /* ECMA-262 3rd Edition 11.13.1 */
2941 static HRESULT interp_set_member(script_ctx_t *ctx)
2943 jsval_t objv, namev, value;
2944 const WCHAR *name;
2945 IDispatch *obj;
2946 HRESULT hres;
2948 value = stack_pop(ctx);
2949 namev = stack_pop(ctx);
2950 assert(is_string(namev));
2951 objv = stack_pop(ctx);
2953 TRACE("%s.%s = %s\n", debugstr_jsval(objv), debugstr_jsval(namev), debugstr_jsval(value));
2955 hres = to_object(ctx, objv, &obj);
2956 jsval_release(objv);
2957 if(SUCCEEDED(hres) && !(name = jsstr_flatten(get_string(namev)))) {
2958 IDispatch_Release(obj);
2959 hres = E_OUTOFMEMORY;
2961 if(SUCCEEDED(hres)) {
2962 hres = disp_propput_name(ctx, obj, name, value);
2963 IDispatch_Release(obj);
2964 jsstr_release(get_string(namev));
2966 if(FAILED(hres)) {
2967 WARN("failed %08lx\n", hres);
2968 jsval_release(value);
2969 return hres;
2972 return stack_push(ctx, value);
2975 /* JScript extension */
2976 static HRESULT interp_assign_call(script_ctx_t *ctx)
2978 const unsigned argc = get_op_uint(ctx, 0);
2979 exprval_t ref;
2980 jsval_t v;
2981 HRESULT hres;
2983 TRACE("%u\n", argc);
2985 if(!stack_topn_exprval(ctx, argc+1, &ref))
2986 return JS_E_ILLEGAL_ASSIGN;
2988 hres = exprval_call(ctx, &ref, DISPATCH_PROPERTYPUT, argc+1, stack_args(ctx, argc+1), NULL);
2989 if(FAILED(hres))
2990 return hres;
2992 v = stack_pop(ctx);
2993 stack_popn(ctx, argc+2);
2994 return stack_push(ctx, v);
2997 static HRESULT interp_undefined(script_ctx_t *ctx)
2999 TRACE("\n");
3001 return stack_push(ctx, jsval_undefined());
3004 static HRESULT interp_jmp(script_ctx_t *ctx)
3006 const unsigned arg = get_op_uint(ctx, 0);
3008 TRACE("%u\n", arg);
3010 jmp_abs(ctx, arg);
3011 return S_OK;
3014 static HRESULT interp_jmp_z(script_ctx_t *ctx)
3016 const unsigned arg = get_op_uint(ctx, 0);
3017 BOOL b;
3018 jsval_t v;
3019 HRESULT hres;
3021 TRACE("\n");
3023 v = stack_pop(ctx);
3024 hres = to_boolean(v, &b);
3025 jsval_release(v);
3026 if(FAILED(hres))
3027 return hres;
3029 if(b)
3030 jmp_next(ctx);
3031 else
3032 jmp_abs(ctx, arg);
3033 return S_OK;
3036 static HRESULT interp_pop(script_ctx_t *ctx)
3038 const unsigned arg = get_op_uint(ctx, 0);
3040 TRACE("%u\n", arg);
3042 stack_popn(ctx, arg);
3043 return S_OK;
3046 static HRESULT interp_ret(script_ctx_t *ctx)
3048 const unsigned clear_ret = get_op_uint(ctx, 0);
3049 call_frame_t *frame = ctx->call_ctx;
3051 TRACE("\n");
3053 if(clear_ret)
3054 jsval_release(steal_ret(frame));
3056 if((frame->flags & EXEC_CONSTRUCTOR) && !is_object_instance(frame->ret)) {
3057 jsval_release(frame->ret);
3058 IDispatch_AddRef(frame->this_obj);
3059 frame->ret = jsval_disp(frame->this_obj);
3062 jmp_abs(ctx, -1);
3063 return S_OK;
3066 static HRESULT interp_setret(script_ctx_t *ctx)
3068 call_frame_t *frame = ctx->call_ctx;
3070 TRACE("\n");
3072 jsval_release(frame->ret);
3073 frame->ret = stack_pop(ctx);
3074 return S_OK;
3077 static HRESULT interp_push_acc(script_ctx_t *ctx)
3079 HRESULT hres;
3081 TRACE("\n");
3083 hres = stack_push(ctx, ctx->acc);
3084 if(SUCCEEDED(hres))
3085 ctx->acc = jsval_undefined();
3086 return hres;
3089 typedef HRESULT (*op_func_t)(script_ctx_t*);
3091 static const op_func_t op_funcs[] = {
3092 #define X(x,a,b,c) interp_##x,
3093 OP_LIST
3094 #undef X
3097 static const unsigned op_move[] = {
3098 #define X(a,x,b,c) x,
3099 OP_LIST
3100 #undef X
3103 static void pop_call_frame(script_ctx_t *ctx)
3105 call_frame_t *frame = ctx->call_ctx;
3107 frame->stack_base -= frame->pop_locals + frame->pop_variables;
3109 assert(frame->scope == frame->base_scope);
3111 /* If current scope will be kept alive, we need to transfer local variables to its variable object. */
3112 if(frame->scope && frame->scope->dispex.ref > 1) {
3113 HRESULT hres = detach_variable_object(ctx, frame, TRUE);
3114 if(FAILED(hres))
3115 ERR("Failed to detach variable object: %08lx\n", hres);
3118 if(frame->arguments_obj)
3119 detach_arguments_object(frame);
3120 if(frame->scope)
3121 scope_release(frame->scope);
3123 if(frame->pop_variables)
3124 stack_popn(ctx, frame->pop_variables);
3125 stack_popn(ctx, frame->pop_locals);
3127 ctx->call_ctx = frame->prev_frame;
3129 if(frame->function_instance)
3130 jsdisp_release(frame->function_instance);
3131 if(frame->variable_obj)
3132 jsdisp_release(frame->variable_obj);
3133 if(frame->this_obj)
3134 IDispatch_Release(frame->this_obj);
3135 jsval_release(frame->ret);
3136 release_bytecode(frame->bytecode);
3137 free(frame);
3140 static void print_backtrace(script_ctx_t *ctx)
3142 unsigned depth = 0, i, line, char_pos;
3143 call_frame_t *frame;
3145 for(frame = ctx->call_ctx; frame; frame = frame->prev_frame) {
3146 WARN("%u\t", depth);
3147 depth++;
3149 if(frame->this_obj)
3150 WARN("%p->", frame->this_obj);
3151 WARN("%s(", frame->function->name ? debugstr_w(frame->function->name) : "[unnamed]");
3152 if(frame->base_scope && frame->base_scope->frame) {
3153 for(i=0; i < frame->argc; i++) {
3154 if(i < frame->function->param_cnt)
3155 WARN("%s%s=%s", i ? ", " : "", debugstr_w(frame->function->params[i]),
3156 debugstr_jsval(ctx->stack[local_off(frame, -i-1)]));
3157 else
3158 WARN("%s%s", i ? ", " : "", debugstr_jsval(ctx->stack[local_off(frame, -i-1)]));
3160 }else {
3161 WARN("[detached frame]");
3163 line = get_location_line(frame->bytecode, frame->bytecode->instrs[frame->ip].loc, &char_pos);
3164 WARN(") context %s line %u char %u\n", wine_dbgstr_longlong(frame->bytecode->source_context), line, char_pos);
3166 if(!(frame->flags & EXEC_RETURN_TO_INTERP)) {
3167 WARN("%u\t[native code]\n", depth);
3168 depth++;
3173 static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres)
3175 except_frame_t *except_frame;
3176 jsexcept_t *ei = ctx->ei;
3177 call_frame_t *frame;
3178 jsval_t except_val;
3179 unsigned catch_off;
3180 HRESULT hres;
3182 if(WARN_ON(jscript)) {
3183 jsdisp_t *error_obj;
3184 jsval_t msg;
3186 WARN("Exception %08lx %s", exception_hres, debugstr_jsval(ei->valid_value ? ei->value : jsval_undefined()));
3187 if(ei->valid_value && jsval_type(ei->value) == JSV_OBJECT) {
3188 error_obj = to_jsdisp(get_object(ei->value));
3189 if(error_obj) {
3190 hres = jsdisp_propget_name(error_obj, L"message", &msg);
3191 if(SUCCEEDED(hres)) {
3192 WARN(" (message %s)", debugstr_jsval(msg));
3193 jsval_release(msg);
3197 WARN(" in:\n");
3199 print_backtrace(ctx);
3202 frame = ctx->call_ctx;
3203 if(exception_hres != DISP_E_EXCEPTION)
3204 throw_error(ctx, exception_hres, NULL);
3205 set_error_location(ei, frame->bytecode, frame->bytecode->instrs[frame->ip].loc, IDS_RUNTIME_ERROR, NULL);
3207 while(!frame->except_frame) {
3208 DWORD flags;
3210 while(frame->scope != frame->base_scope)
3211 scope_pop(&frame->scope);
3213 stack_popn(ctx, ctx->stack_top-frame->stack_base);
3215 flags = frame->flags;
3216 pop_call_frame(ctx);
3217 if(!(flags & EXEC_RETURN_TO_INTERP))
3218 return DISP_E_EXCEPTION;
3219 frame = ctx->call_ctx;
3222 except_frame = frame->except_frame;
3223 catch_off = except_frame->catch_off;
3225 assert(except_frame->stack_top <= ctx->stack_top);
3226 stack_popn(ctx, ctx->stack_top - except_frame->stack_top);
3228 while(except_frame->scope != frame->scope)
3229 scope_pop(&frame->scope);
3231 frame->ip = catch_off ? catch_off : except_frame->finally_off;
3232 assert(!catch_off || frame->bytecode->instrs[frame->ip].op == OP_enter_catch);
3234 if(ei->valid_value) {
3235 except_val = ctx->ei->value;
3236 ei->valid_value = FALSE;
3237 }else {
3238 jsdisp_t *err;
3239 if(!(err = create_builtin_error(ctx)))
3240 return E_OUTOFMEMORY;
3241 except_val = jsval_obj(err);
3244 /* keep current except_frame if we're entering catch block with finally block associated */
3245 if(catch_off && except_frame->finally_off) {
3246 except_frame->catch_off = 0;
3247 }else {
3248 frame->except_frame = except_frame->next;
3249 free(except_frame);
3252 hres = stack_push(ctx, except_val);
3253 if(FAILED(hres))
3254 return hres;
3256 if(!catch_off)
3257 hres = stack_push(ctx, jsval_bool(FALSE));
3258 return hres;
3261 static HRESULT enter_bytecode(script_ctx_t *ctx, jsval_t *r)
3263 call_frame_t *frame;
3264 jsop_t op;
3265 HRESULT hres = S_OK;
3267 TRACE("\n");
3269 while(1) {
3270 frame = ctx->call_ctx;
3271 op = frame->bytecode->instrs[frame->ip].op;
3272 hres = op_funcs[op](ctx);
3273 if(FAILED(hres)) {
3274 hres = unwind_exception(ctx, hres);
3275 if(FAILED(hres))
3276 return hres;
3277 }else if(frame->ip == -1) {
3278 const DWORD return_to_interp = frame->flags & EXEC_RETURN_TO_INTERP;
3280 assert(ctx->stack_top == frame->stack_base);
3281 assert(frame->scope == frame->base_scope);
3283 if(return_to_interp) {
3284 jsval_release(ctx->acc);
3285 ctx->acc = steal_ret(frame);
3286 }else if(r) {
3287 *r = steal_ret(frame);
3289 pop_call_frame(ctx);
3290 if(!return_to_interp)
3291 break;
3292 }else {
3293 frame->ip += op_move[op];
3297 return S_OK;
3300 static HRESULT bind_event_target(script_ctx_t *ctx, function_code_t *func, jsdisp_t *func_obj)
3302 IBindEventHandler *target;
3303 exprval_t exprval;
3304 IDispatch *disp;
3305 jsval_t v;
3306 HRESULT hres;
3308 hres = identifier_eval(ctx, func->event_target, &exprval);
3309 if(FAILED(hres))
3310 return hres;
3312 hres = exprval_to_value(ctx, &exprval, &v);
3313 if(FAILED(hres))
3314 return hres;
3316 if(!is_object_instance(v)) {
3317 FIXME("Can't bind to %s\n", debugstr_jsval(v));
3318 jsval_release(v);
3321 disp = get_object(v);
3322 hres = IDispatch_QueryInterface(disp, &IID_IBindEventHandler, (void**)&target);
3323 if(SUCCEEDED(hres)) {
3324 hres = IBindEventHandler_BindHandler(target, func->name, (IDispatch*)&func_obj->IDispatchEx_iface);
3325 IBindEventHandler_Release(target);
3326 if(FAILED(hres))
3327 WARN("BindEvent failed: %08lx\n", hres);
3328 }else {
3329 FIXME("No IBindEventHandler, not yet supported binding\n");
3332 IDispatch_Release(disp);
3333 return hres;
3336 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)
3338 const unsigned orig_stack = ctx->stack_top;
3339 scope_chain_t *scope;
3340 unsigned i;
3341 jsval_t v;
3342 HRESULT hres;
3344 /* If arguments are already on the stack, we may use them. */
3345 if(argv + argc == ctx->stack + ctx->stack_top) {
3346 frame->arguments_off = argv - ctx->stack;
3347 i = argc;
3348 }else {
3349 frame->arguments_off = ctx->stack_top;
3350 for(i = 0; i < argc; i++) {
3351 hres = jsval_copy(argv[i], &v);
3352 if(SUCCEEDED(hres))
3353 hres = stack_push(ctx, v);
3354 if(FAILED(hres)) {
3355 stack_popn(ctx, i);
3356 return hres;
3361 /* If fewer than declared arguments were passed, fill remaining with undefined value. */
3362 for(; i < frame->function->param_cnt; i++) {
3363 hres = stack_push(ctx, jsval_undefined());
3364 if(FAILED(hres)) {
3365 stack_popn(ctx, ctx->stack_top - orig_stack);
3366 return hres;
3370 frame->pop_locals = ctx->stack_top - orig_stack;
3372 frame->variables_off = ctx->stack_top;
3374 for(i = 0; i < frame->function->var_cnt; i++) {
3375 hres = stack_push(ctx, jsval_undefined());
3376 if(FAILED(hres)) {
3377 stack_popn(ctx, ctx->stack_top - orig_stack);
3378 return hres;
3382 frame->pop_variables = i;
3384 hres = scope_push(ctx, scope_chain, to_disp(variable_object), &scope);
3385 if(FAILED(hres)) {
3386 stack_popn(ctx, ctx->stack_top - orig_stack);
3387 return hres;
3390 for(i = 0; i < frame->function->func_cnt; i++) {
3391 if(frame->function->funcs[i].local_ref != INVALID_LOCAL_REF
3392 && !frame->function->funcs[i].scope_index)
3394 jsdisp_t *func_obj;
3395 unsigned off;
3397 hres = create_source_function(ctx, frame->bytecode, frame->function->funcs+i, scope, &func_obj);
3398 if(FAILED(hres)) {
3399 stack_popn(ctx, ctx->stack_top - orig_stack);
3400 scope_release(scope);
3401 return hres;
3404 off = local_off(frame, frame->function->funcs[i].local_ref);
3405 jsval_release(ctx->stack[off]);
3406 ctx->stack[off] = jsval_obj(func_obj);
3410 scope->frame = frame;
3411 frame->base_scope = frame->scope = scope;
3412 return S_OK;
3415 HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, function_code_t *function, scope_chain_t *scope,
3416 IDispatch *this_obj, jsdisp_t *function_instance, unsigned argc, jsval_t *argv, jsval_t *r)
3418 jsdisp_t *variable_obj;
3419 call_frame_t *frame;
3420 unsigned i;
3421 HRESULT hres;
3423 if(!ctx->stack) {
3424 ctx->stack = malloc(stack_size * sizeof(*ctx->stack));
3425 if(!ctx->stack)
3426 return E_OUTOFMEMORY;
3429 if(bytecode->named_item) {
3430 if(!bytecode->named_item->script_obj) {
3431 hres = create_named_item_script_obj(ctx, bytecode->named_item);
3432 if(FAILED(hres)) return hres;
3436 if(!ctx->ei->enter_notified) {
3437 ctx->ei->enter_notified = TRUE;
3438 IActiveScriptSite_OnEnterScript(ctx->site);
3441 for(i = 0; i < function->func_cnt; i++) {
3442 jsdisp_t *func_obj;
3444 if(!function->funcs[i].event_target)
3445 continue;
3447 if (function->funcs[i].scope_index)
3449 /* TODO: Add tests and handle in interp_push_scope(). */
3450 FIXME("Event target with scope index are not properly handled.\n");
3453 hres = create_source_function(ctx, bytecode, function->funcs+i, scope, &func_obj);
3454 if(FAILED(hres))
3455 return hres;
3457 hres = bind_event_target(ctx, function->funcs+i, func_obj);
3458 jsdisp_release(func_obj);
3459 if(FAILED(hres))
3460 return hres;
3463 if((flags & EXEC_EVAL) && ctx->call_ctx) {
3464 variable_obj = jsdisp_addref(ctx->call_ctx->variable_obj);
3465 }else if(!(flags & (EXEC_GLOBAL | EXEC_EVAL))) {
3466 hres = create_dispex(ctx, NULL, NULL, &variable_obj);
3467 if(FAILED(hres)) return hres;
3468 }else if(bytecode->named_item) {
3469 variable_obj = jsdisp_addref(bytecode->named_item->script_obj);
3470 }else {
3471 variable_obj = jsdisp_addref(ctx->global);
3474 if(flags & (EXEC_GLOBAL | EXEC_EVAL)) {
3475 named_item_t *item = bytecode->named_item;
3476 DISPID id;
3478 for(i=0; i < function->var_cnt; i++) {
3479 TRACE("[%d] %s %d\n", i, debugstr_w(function->variables[i].name), function->variables[i].func_id);
3480 if(function->variables[i].func_id != -1) {
3481 jsdisp_t *func_obj;
3483 if (function->funcs[function->variables[i].func_id].scope_index && flags & EXEC_EVAL)
3485 /* TODO: Add tests and handle in interp_push_scope(). */
3486 FIXME("Functions with scope index inside eval() are not properly handled.\n");
3489 hres = create_source_function(ctx, bytecode, function->funcs+function->variables[i].func_id, scope, &func_obj);
3490 if(FAILED(hres))
3491 goto fail;
3493 hres = jsdisp_propput_name(variable_obj, function->variables[i].name, jsval_obj(func_obj));
3494 jsdisp_release(func_obj);
3495 continue;
3498 if(item && !(item->flags & SCRIPTITEM_CODEONLY)
3499 && SUCCEEDED(disp_get_id(ctx, item->disp, function->variables[i].name, function->variables[i].name, 0, &id)))
3500 continue;
3502 if(!item && (flags & EXEC_GLOBAL) && lookup_global_members(ctx, function->variables[i].name, NULL))
3503 continue;
3505 hres = jsdisp_get_id(variable_obj, function->variables[i].name, fdexNameEnsure, &id);
3506 if(FAILED(hres))
3507 goto fail;
3511 if(this_obj) {
3512 jsdisp_t *jsthis = to_jsdisp(this_obj);
3514 if(jsthis && jsthis->builtin_info->class == JSCLASS_GLOBAL)
3515 this_obj = NULL;
3518 if(ctx->call_ctx && (flags & EXEC_EVAL)) {
3519 hres = detach_variable_object(ctx, ctx->call_ctx, FALSE);
3520 if(FAILED(hres))
3521 goto fail;
3524 frame = calloc(1, sizeof(*frame));
3525 if(!frame) {
3526 hres = E_OUTOFMEMORY;
3527 goto fail;
3530 frame->function = function;
3531 frame->ret = jsval_undefined();
3532 frame->argc = argc;
3533 frame->bytecode = bytecode_addref(bytecode);
3535 if(!(flags & (EXEC_GLOBAL|EXEC_EVAL))) {
3536 hres = setup_scope(ctx, frame, scope, variable_obj, argc, argv);
3537 if(FAILED(hres)) {
3538 release_bytecode(frame->bytecode);
3539 free(frame);
3540 goto fail;
3542 }else if(scope) {
3543 frame->base_scope = frame->scope = scope_addref(scope);
3546 frame->ip = function->instr_off;
3547 frame->stack_base = ctx->stack_top;
3548 if(this_obj) {
3549 frame->this_obj = this_obj;
3550 IDispatch_AddRef(frame->this_obj);
3553 if(function_instance)
3554 frame->function_instance = jsdisp_addref(function_instance);
3556 frame->flags = flags;
3557 frame->variable_obj = variable_obj;
3559 frame->prev_frame = ctx->call_ctx;
3560 ctx->call_ctx = frame;
3562 if(flags & EXEC_RETURN_TO_INTERP) {
3564 * We're called directly from interpreter, so we may just setup call frame and return.
3565 * Already running interpreter will take care of execution.
3567 if(r)
3568 *r = jsval_undefined();
3569 return S_OK;
3572 return enter_bytecode(ctx, r);
3574 fail:
3575 jsdisp_release(variable_obj);
3576 return hres;