a731930fd8835abb2265b9f44f821cb085246999
[reactos.git] / dll / win32 / jscript / engine.c
1 /*
2 * Copyright 2008,2011 Jacek Caban for CodeWeavers
3 *
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.
8 *
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.
13 *
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
17 */
18
19 #include "jscript.h"
20
21 WINE_DECLARE_DEBUG_CHANNEL(jscript_except);
22
23 static const WCHAR booleanW[] = {'b','o','o','l','e','a','n',0};
24 static const WCHAR functionW[] = {'f','u','n','c','t','i','o','n',0};
25 static const WCHAR numberW[] = {'n','u','m','b','e','r',0};
26 static const WCHAR objectW[] = {'o','b','j','e','c','t',0};
27 static const WCHAR stringW[] = {'s','t','r','i','n','g',0};
28 static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
29 static const WCHAR unknownW[] = {'u','n','k','n','o','w','n',0};
30
31 struct _except_frame_t {
32 unsigned stack_top;
33 scope_chain_t *scope;
34 unsigned catch_off;
35 unsigned finally_off;
36
37 except_frame_t *next;
38 };
39
40 typedef struct {
41 enum {
42 EXPRVAL_JSVAL,
43 EXPRVAL_IDREF,
44 EXPRVAL_STACK_REF,
45 EXPRVAL_INVALID
46 } type;
47 union {
48 jsval_t val;
49 struct {
50 IDispatch *disp;
51 DISPID id;
52 } idref;
53 unsigned off;
54 HRESULT hres;
55 } u;
56 } exprval_t;
57
58 static HRESULT stack_push(script_ctx_t *ctx, jsval_t v)
59 {
60 if(!ctx->stack_size) {
61 ctx->stack = heap_alloc(16*sizeof(*ctx->stack));
62 if(!ctx->stack)
63 return E_OUTOFMEMORY;
64 ctx->stack_size = 16;
65 }else if(ctx->stack_size == ctx->stack_top) {
66 jsval_t *new_stack;
67
68 new_stack = heap_realloc(ctx->stack, ctx->stack_size*2*sizeof(*new_stack));
69 if(!new_stack) {
70 jsval_release(v);
71 return E_OUTOFMEMORY;
72 }
73
74 ctx->stack = new_stack;
75 ctx->stack_size *= 2;
76 }
77
78 ctx->stack[ctx->stack_top++] = v;
79 return S_OK;
80 }
81
82 static inline HRESULT stack_push_string(script_ctx_t *ctx, const WCHAR *str)
83 {
84 jsstr_t *v;
85
86 v = jsstr_alloc(str);
87 if(!v)
88 return E_OUTOFMEMORY;
89
90 return stack_push(ctx, jsval_string(v));
91 }
92
93 static inline jsval_t stack_top(script_ctx_t *ctx)
94 {
95 assert(ctx->stack_top > ctx->call_ctx->stack_base);
96 return ctx->stack[ctx->stack_top-1];
97 }
98
99 static inline jsval_t *stack_top_ref(script_ctx_t *ctx, unsigned n)
100 {
101 assert(ctx->stack_top > ctx->call_ctx->stack_base+n);
102 return ctx->stack+ctx->stack_top-1-n;
103 }
104
105 static inline jsval_t stack_topn(script_ctx_t *ctx, unsigned n)
106 {
107 return *stack_top_ref(ctx, n);
108 }
109
110 static inline jsval_t *stack_args(script_ctx_t *ctx, unsigned n)
111 {
112 if(!n)
113 return NULL;
114 assert(ctx->stack_top > ctx->call_ctx->stack_base+n-1);
115 return ctx->stack + ctx->stack_top-n;
116 }
117
118 static inline jsval_t stack_pop(script_ctx_t *ctx)
119 {
120 assert(ctx->stack_top > ctx->call_ctx->stack_base);
121 return ctx->stack[--ctx->stack_top];
122 }
123
124 static void stack_popn(script_ctx_t *ctx, unsigned n)
125 {
126 while(n--)
127 jsval_release(stack_pop(ctx));
128 }
129
130 static HRESULT stack_pop_number(script_ctx_t *ctx, double *r)
131 {
132 jsval_t v;
133 HRESULT hres;
134
135 v = stack_pop(ctx);
136 hres = to_number(ctx, v, r);
137 jsval_release(v);
138 return hres;
139 }
140
141 static HRESULT stack_pop_object(script_ctx_t *ctx, IDispatch **r)
142 {
143 jsval_t v;
144 HRESULT hres;
145
146 v = stack_pop(ctx);
147 if(is_object_instance(v)) {
148 if(!get_object(v))
149 return throw_type_error(ctx, JS_E_OBJECT_REQUIRED, NULL);
150 *r = get_object(v);
151 return S_OK;
152 }
153
154 hres = to_object(ctx, v, r);
155 jsval_release(v);
156 return hres;
157 }
158
159 static inline HRESULT stack_pop_int(script_ctx_t *ctx, INT *r)
160 {
161 return to_int32(ctx, stack_pop(ctx), r);
162 }
163
164 static inline HRESULT stack_pop_uint(script_ctx_t *ctx, DWORD *r)
165 {
166 return to_uint32(ctx, stack_pop(ctx), r);
167 }
168
169 static inline unsigned local_off(call_frame_t *frame, int ref)
170 {
171 return ref < 0
172 ? frame->arguments_off - ref-1
173 : frame->variables_off + ref;
174 }
175
176 static inline BSTR local_name(call_frame_t *frame, int ref)
177 {
178 return ref < 0 ? frame->function->params[-ref-1] : frame->function->variables[ref].name;
179 }
180
181 /* Steals input reference even on failure. */
182 static HRESULT stack_push_exprval(script_ctx_t *ctx, exprval_t *val)
183 {
184 HRESULT hres;
185
186 switch(val->type) {
187 case EXPRVAL_JSVAL:
188 assert(0);
189 case EXPRVAL_IDREF:
190 hres = stack_push(ctx, jsval_disp(val->u.idref.disp));
191 if(SUCCEEDED(hres))
192 hres = stack_push(ctx, jsval_number(val->u.idref.id));
193 else
194 IDispatch_Release(val->u.idref.disp);
195 return hres;
196 case EXPRVAL_STACK_REF:
197 hres = stack_push(ctx, jsval_number(val->u.off));
198 if(SUCCEEDED(hres))
199 hres = stack_push(ctx, jsval_undefined());
200 return hres;
201 case EXPRVAL_INVALID:
202 hres = stack_push(ctx, jsval_undefined());
203 if(SUCCEEDED(hres))
204 hres = stack_push(ctx, jsval_number(val->u.hres));
205 return hres;
206 }
207
208 assert(0);
209 return E_FAIL;
210 }
211
212 static BOOL stack_topn_exprval(script_ctx_t *ctx, unsigned n, exprval_t *r)
213 {
214 jsval_t v = stack_topn(ctx, n+1);
215
216 switch(jsval_type(v)) {
217 case JSV_NUMBER: {
218 call_frame_t *frame = ctx->call_ctx;
219 unsigned off = get_number(v);
220
221 if(!frame->base_scope->frame && off >= frame->arguments_off) {
222 DISPID id;
223 BSTR name;
224 HRESULT hres;
225
226 /* Got stack reference in deoptimized code. Need to convert it back to variable object reference. */
227
228 assert(off < frame->variables_off + frame->function->var_cnt);
229 name = off >= frame->variables_off
230 ? frame->function->variables[off - frame->variables_off].name
231 : frame->function->params[off - frame->arguments_off];
232 hres = jsdisp_get_id(ctx->call_ctx->base_scope->jsobj, name, 0, &id);
233 if(FAILED(hres)) {
234 r->type = EXPRVAL_INVALID;
235 r->u.hres = hres;
236 return FALSE;
237 }
238
239 *stack_top_ref(ctx, n+1) = jsval_obj(jsdisp_addref(frame->base_scope->jsobj));
240 *stack_top_ref(ctx, n) = jsval_number(id);
241 r->type = EXPRVAL_IDREF;
242 r->u.idref.disp = frame->base_scope->obj;
243 r->u.idref.id = id;
244 return TRUE;
245 }
246
247 r->type = EXPRVAL_STACK_REF;
248 r->u.off = off;
249 return TRUE;
250 }
251 case JSV_OBJECT:
252 r->type = EXPRVAL_IDREF;
253 r->u.idref.disp = get_object(v);
254 assert(is_number(stack_topn(ctx, n)));
255 r->u.idref.id = get_number(stack_topn(ctx, n));
256 return TRUE;
257 case JSV_UNDEFINED:
258 r->type = EXPRVAL_INVALID;
259 assert(is_number(stack_topn(ctx, n)));
260 r->u.hres = get_number(stack_topn(ctx, n));
261 return FALSE;
262 default:
263 assert(0);
264 return FALSE;
265 }
266 }
267
268 static inline BOOL stack_pop_exprval(script_ctx_t *ctx, exprval_t *r)
269 {
270 BOOL ret = stack_topn_exprval(ctx, 0, r);
271 ctx->stack_top -= 2;
272 return ret;
273 }
274
275 static HRESULT exprval_propput(script_ctx_t *ctx, exprval_t *ref, jsval_t v)
276 {
277 switch(ref->type) {
278 case EXPRVAL_STACK_REF: {
279 jsval_t *r = ctx->stack + ref->u.off;
280 jsval_release(*r);
281 return jsval_copy(v, r);
282 }
283 case EXPRVAL_IDREF:
284 return disp_propput(ctx, ref->u.idref.disp, ref->u.idref.id, v);
285 default:
286 assert(0);
287 return E_FAIL;
288 }
289 }
290
291 static HRESULT exprval_propget(script_ctx_t *ctx, exprval_t *ref, jsval_t *r)
292 {
293 switch(ref->type) {
294 case EXPRVAL_STACK_REF:
295 return jsval_copy(ctx->stack[ref->u.off], r);
296 case EXPRVAL_IDREF:
297 return disp_propget(ctx, ref->u.idref.disp, ref->u.idref.id, r);
298 default:
299 assert(0);
300 return E_FAIL;
301 }
302 }
303
304 static HRESULT exprval_call(script_ctx_t *ctx, exprval_t *ref, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
305 {
306 switch(ref->type) {
307 case EXPRVAL_STACK_REF: {
308 jsval_t v = ctx->stack[ref->u.off];
309
310 if(!is_object_instance(v)) {
311 FIXME("invoke %s\n", debugstr_jsval(v));
312 return E_FAIL;
313 }
314
315 return disp_call_value(ctx, get_object(v), NULL, flags, argc, argv, r);
316 }
317 case EXPRVAL_IDREF:
318 return disp_call(ctx, ref->u.idref.disp, ref->u.idref.id, flags, argc, argv, r);
319 default:
320 assert(0);
321 return E_FAIL;
322 }
323 }
324
325 /* ECMA-262 3rd Edition 8.7.1 */
326 /* Steals input reference. */
327 static HRESULT exprval_to_value(script_ctx_t *ctx, exprval_t *ref, jsval_t *r)
328 {
329 HRESULT hres;
330
331 if(ref->type == EXPRVAL_JSVAL) {
332 *r = ref->u.val;
333 return S_OK;
334 }
335
336 hres = exprval_propget(ctx, ref, r);
337
338 if(ref->type == EXPRVAL_IDREF)
339 IDispatch_Release(ref->u.idref.disp);
340 return hres;
341 }
342
343 static void exprval_release(exprval_t *val)
344 {
345 switch(val->type) {
346 case EXPRVAL_JSVAL:
347 jsval_release(val->u.val);
348 return;
349 case EXPRVAL_IDREF:
350 if(val->u.idref.disp)
351 IDispatch_Release(val->u.idref.disp);
352 return;
353 case EXPRVAL_STACK_REF:
354 case EXPRVAL_INVALID:
355 return;
356 }
357 }
358
359 static inline void exprval_set_exception(exprval_t *val, HRESULT hres)
360 {
361 val->type = EXPRVAL_INVALID;
362 val->u.hres = hres;
363 }
364
365 static inline void exprval_set_disp_ref(exprval_t *ref, IDispatch *obj, DISPID id)
366 {
367 ref->type = EXPRVAL_IDREF;
368 #ifdef __REACTOS__ /* FIXME: Inspect */
369 IDispatch_AddRef(obj);
370 ref->u.idref.disp = obj;
371 #else
372 IDispatch_AddRef(ref->u.idref.disp = obj);
373 #endif
374 ref->u.idref.id = id;
375 }
376
377 static inline jsval_t steal_ret(call_frame_t *frame)
378 {
379 jsval_t r = frame->ret;
380 frame->ret = jsval_undefined();
381 return r;
382 }
383
384 static inline void clear_ret(call_frame_t *frame)
385 {
386 jsval_release(steal_ret(frame));
387 }
388
389 static HRESULT scope_push(scope_chain_t *scope, jsdisp_t *jsobj, IDispatch *obj, scope_chain_t **ret)
390 {
391 scope_chain_t *new_scope;
392
393 new_scope = heap_alloc(sizeof(scope_chain_t));
394 if(!new_scope)
395 return E_OUTOFMEMORY;
396
397 new_scope->ref = 1;
398
399 IDispatch_AddRef(obj);
400 new_scope->jsobj = jsobj;
401 new_scope->obj = obj;
402 new_scope->frame = NULL;
403 new_scope->next = scope ? scope_addref(scope) : NULL;
404
405 *ret = new_scope;
406 return S_OK;
407 }
408
409 static void scope_pop(scope_chain_t **scope)
410 {
411 scope_chain_t *tmp;
412
413 tmp = *scope;
414 *scope = tmp->next;
415 scope_release(tmp);
416 }
417
418 void clear_ei(script_ctx_t *ctx)
419 {
420 memset(&ctx->ei.ei, 0, sizeof(ctx->ei.ei));
421 jsval_release(ctx->ei.val);
422 ctx->ei.val = jsval_undefined();
423 }
424
425 void scope_release(scope_chain_t *scope)
426 {
427 if(--scope->ref)
428 return;
429
430 if(scope->next)
431 scope_release(scope->next);
432
433 IDispatch_Release(scope->obj);
434 heap_free(scope);
435 }
436
437 static HRESULT disp_get_id(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name, BSTR name_bstr, DWORD flags, DISPID *id)
438 {
439 IDispatchEx *dispex;
440 jsdisp_t *jsdisp;
441 BSTR bstr;
442 HRESULT hres;
443
444 jsdisp = iface_to_jsdisp(disp);
445 if(jsdisp) {
446 hres = jsdisp_get_id(jsdisp, name, flags, id);
447 jsdisp_release(jsdisp);
448 return hres;
449 }
450
451 if(name_bstr) {
452 bstr = name_bstr;
453 }else {
454 bstr = SysAllocString(name);
455 if(!bstr)
456 return E_OUTOFMEMORY;
457 }
458
459 *id = 0;
460 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
461 if(SUCCEEDED(hres)) {
462 hres = IDispatchEx_GetDispID(dispex, bstr, make_grfdex(ctx, flags|fdexNameCaseSensitive), id);
463 IDispatchEx_Release(dispex);
464 }else {
465 TRACE("using IDispatch\n");
466 hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, id);
467 }
468
469 if(name_bstr != bstr)
470 SysFreeString(bstr);
471 return hres;
472 }
473
474 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, BOOL *ret)
475 {
476 IObjectIdentity *identity;
477 IUnknown *unk1, *unk2;
478 HRESULT hres;
479
480 if(disp1 == disp2) {
481 *ret = TRUE;
482 return S_OK;
483 }
484
485 if(!disp1 || !disp2) {
486 *ret = FALSE;
487 return S_OK;
488 }
489
490 hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
491 if(FAILED(hres))
492 return hres;
493
494 hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
495 if(FAILED(hres)) {
496 IUnknown_Release(unk1);
497 return hres;
498 }
499
500 if(unk1 == unk2) {
501 *ret = TRUE;
502 }else {
503 hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
504 if(SUCCEEDED(hres)) {
505 hres = IObjectIdentity_IsEqualObject(identity, unk2);
506 IObjectIdentity_Release(identity);
507 *ret = hres == S_OK;
508 }else {
509 *ret = FALSE;
510 }
511 }
512
513 IUnknown_Release(unk1);
514 IUnknown_Release(unk2);
515 return S_OK;
516 }
517
518 /* ECMA-262 3rd Edition 11.9.6 */
519 static HRESULT equal2_values(jsval_t lval, jsval_t rval, BOOL *ret)
520 {
521 jsval_type_t type = jsval_type(lval);
522
523 TRACE("\n");
524
525 if(type != jsval_type(rval)) {
526 if(is_null_instance(lval))
527 *ret = is_null_instance(rval);
528 else
529 *ret = FALSE;
530 return S_OK;
531 }
532
533 switch(type) {
534 case JSV_UNDEFINED:
535 case JSV_NULL:
536 *ret = TRUE;
537 break;
538 case JSV_OBJECT:
539 return disp_cmp(get_object(lval), get_object(rval), ret);
540 case JSV_STRING:
541 *ret = jsstr_eq(get_string(lval), get_string(rval));
542 break;
543 case JSV_NUMBER:
544 *ret = get_number(lval) == get_number(rval);
545 break;
546 case JSV_BOOL:
547 *ret = !get_bool(lval) == !get_bool(rval);
548 break;
549 case JSV_VARIANT:
550 FIXME("VARIANT not implemented\n");
551 return E_NOTIMPL;
552 }
553
554 return S_OK;
555 }
556
557 /*
558 * Transfers local variables from stack to variable object.
559 * It's slow, so we want to avoid it as much as possible.
560 */
561 static HRESULT detach_variable_object(script_ctx_t *ctx, call_frame_t *frame, BOOL from_release)
562 {
563 unsigned i;
564 HRESULT hres;
565
566 if(!frame->base_scope || !frame->base_scope->frame)
567 return S_OK;
568
569 TRACE("detaching %p\n", frame);
570
571 assert(frame == frame->base_scope->frame);
572 assert(frame->variable_obj == frame->base_scope->jsobj);
573
574 if(!from_release && !frame->arguments_obj) {
575 hres = setup_arguments_object(ctx, frame);
576 if(FAILED(hres))
577 return hres;
578 }
579
580 frame->base_scope->frame = NULL;
581
582 for(i = 0; i < frame->function->locals_cnt; i++) {
583 hres = jsdisp_propput_name(frame->variable_obj, frame->function->locals[i].name,
584 ctx->stack[local_off(frame, frame->function->locals[i].ref)]);
585 if(FAILED(hres))
586 return hres;
587 }
588
589 return S_OK;
590 }
591
592 static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
593 {
594 named_item_t *item;
595 DISPID id;
596 HRESULT hres;
597
598 for(item = ctx->named_items; item; item = item->next) {
599 if(item->flags & SCRIPTITEM_GLOBALMEMBERS) {
600 hres = disp_get_id(ctx, item->disp, identifier, identifier, 0, &id);
601 if(SUCCEEDED(hres)) {
602 if(ret)
603 exprval_set_disp_ref(ret, item->disp, id);
604 return TRUE;
605 }
606 }
607 }
608
609 return FALSE;
610 }
611
612 static int local_ref_cmp(const void *key, const void *ref)
613 {
614 return strcmpW((const WCHAR*)key, ((const local_ref_t*)ref)->name);
615 }
616
617 local_ref_t *lookup_local(const function_code_t *function, const WCHAR *identifier)
618 {
619 return bsearch(identifier, function->locals, function->locals_cnt, sizeof(*function->locals), local_ref_cmp);
620 }
621
622 /* ECMA-262 3rd Edition 10.1.4 */
623 static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
624 {
625 scope_chain_t *scope;
626 named_item_t *item;
627 DISPID id = 0;
628 HRESULT hres;
629
630 TRACE("%s\n", debugstr_w(identifier));
631
632 if(ctx->call_ctx) {
633 for(scope = ctx->call_ctx->scope; scope; scope = scope->next) {
634 if(scope->frame) {
635 function_code_t *func = scope->frame->function;
636 local_ref_t *ref = lookup_local(func, identifier);
637 static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0};
638
639 if(ref) {
640 ret->type = EXPRVAL_STACK_REF;
641 ret->u.off = local_off(scope->frame, ref->ref);
642 TRACE("returning ref %d for %d\n", ret->u.off, ref->ref);
643 return S_OK;
644 }
645
646 if(!strcmpW(identifier, argumentsW)) {
647 hres = detach_variable_object(ctx, scope->frame, FALSE);
648 if(FAILED(hres))
649 return hres;
650 }
651 }
652 if(scope->jsobj)
653 hres = jsdisp_get_id(scope->jsobj, identifier, fdexNameImplicit, &id);
654 else
655 hres = disp_get_id(ctx, scope->obj, identifier, identifier, fdexNameImplicit, &id);
656 if(SUCCEEDED(hres)) {
657 exprval_set_disp_ref(ret, scope->obj, id);
658 return S_OK;
659 }
660 }
661 }
662
663 hres = jsdisp_get_id(ctx->global, identifier, 0, &id);
664 if(SUCCEEDED(hres)) {
665 exprval_set_disp_ref(ret, to_disp(ctx->global), id);
666 return S_OK;
667 }
668
669 for(item = ctx->named_items; item; item = item->next) {
670 if((item->flags & SCRIPTITEM_ISVISIBLE) && !strcmpW(item->name, identifier)) {
671 if(!item->disp) {
672 IUnknown *unk;
673
674 if(!ctx->site)
675 break;
676
677 hres = IActiveScriptSite_GetItemInfo(ctx->site, identifier,
678 SCRIPTINFO_IUNKNOWN, &unk, NULL);
679 if(FAILED(hres)) {
680 WARN("GetItemInfo failed: %08x\n", hres);
681 break;
682 }
683
684 hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp);
685 IUnknown_Release(unk);
686 if(FAILED(hres)) {
687 WARN("object does not implement IDispatch\n");
688 break;
689 }
690 }
691
692 IDispatch_AddRef(item->disp);
693 ret->type = EXPRVAL_JSVAL;
694 ret->u.val = jsval_disp(item->disp);
695 return S_OK;
696 }
697 }
698
699 if(lookup_global_members(ctx, identifier, ret))
700 return S_OK;
701
702 exprval_set_exception(ret, JS_E_UNDEFINED_VARIABLE);
703 return S_OK;
704 }
705
706 static inline BSTR get_op_bstr(script_ctx_t *ctx, int i)
707 {
708 call_frame_t *frame = ctx->call_ctx;
709 return frame->bytecode->instrs[frame->ip].u.arg[i].bstr;
710 }
711
712 static inline unsigned get_op_uint(script_ctx_t *ctx, int i)
713 {
714 call_frame_t *frame = ctx->call_ctx;
715 return frame->bytecode->instrs[frame->ip].u.arg[i].uint;
716 }
717
718 static inline unsigned get_op_int(script_ctx_t *ctx, int i)
719 {
720 call_frame_t *frame = ctx->call_ctx;
721 return frame->bytecode->instrs[frame->ip].u.arg[i].lng;
722 }
723
724 static inline jsstr_t *get_op_str(script_ctx_t *ctx, int i)
725 {
726 call_frame_t *frame = ctx->call_ctx;
727 return frame->bytecode->instrs[frame->ip].u.arg[i].str;
728 }
729
730 static inline double get_op_double(script_ctx_t *ctx)
731 {
732 call_frame_t *frame = ctx->call_ctx;
733 return frame->bytecode->instrs[frame->ip].u.dbl;
734 }
735
736 static inline void jmp_next(script_ctx_t *ctx)
737 {
738 ctx->call_ctx->ip++;
739 }
740
741 static inline void jmp_abs(script_ctx_t *ctx, unsigned dst)
742 {
743 ctx->call_ctx->ip = dst;
744 }
745
746 /* ECMA-262 3rd Edition 12.6.4 */
747 static HRESULT interp_forin(script_ctx_t *ctx)
748 {
749 const HRESULT arg = get_op_uint(ctx, 0);
750 IDispatch *obj = NULL;
751 IDispatchEx *dispex;
752 exprval_t prop_ref;
753 DISPID id;
754 BSTR name = NULL;
755 HRESULT hres;
756
757 TRACE("\n");
758
759 assert(is_number(stack_top(ctx)));
760 id = get_number(stack_top(ctx));
761
762 if(!stack_topn_exprval(ctx, 1, &prop_ref)) {
763 FIXME("invalid ref: %08x\n", prop_ref.u.hres);
764 return E_FAIL;
765 }
766
767 if(is_object_instance(stack_topn(ctx, 3)))
768 obj = get_object(stack_topn(ctx, 3));
769
770 if(obj) {
771 hres = IDispatch_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
772 if(SUCCEEDED(hres)) {
773 hres = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, id, &id);
774 if(hres == S_OK)
775 hres = IDispatchEx_GetMemberName(dispex, id, &name);
776 IDispatchEx_Release(dispex);
777 if(FAILED(hres))
778 return hres;
779 }else {
780 TRACE("No IDispatchEx\n");
781 }
782 }
783
784 if(name) {
785 jsstr_t *str;
786
787 str = jsstr_alloc_len(name, SysStringLen(name));
788 SysFreeString(name);
789 if(!str)
790 return E_OUTOFMEMORY;
791
792 stack_pop(ctx);
793 stack_push(ctx, jsval_number(id)); /* safe, just after pop() */
794
795 hres = exprval_propput(ctx, &prop_ref, jsval_string(str));
796 jsstr_release(str);
797 if(FAILED(hres))
798 return hres;
799
800 jmp_next(ctx);
801 }else {
802 stack_popn(ctx, 4);
803 jmp_abs(ctx, arg);
804 }
805 return S_OK;
806 }
807
808 /* ECMA-262 3rd Edition 12.10 */
809 static HRESULT interp_push_scope(script_ctx_t *ctx)
810 {
811 IDispatch *disp;
812 jsval_t v;
813 HRESULT hres;
814
815 TRACE("\n");
816
817 v = stack_pop(ctx);
818 hres = to_object(ctx, v, &disp);
819 jsval_release(v);
820 if(FAILED(hres))
821 return hres;
822
823 hres = scope_push(ctx->call_ctx->scope, to_jsdisp(disp), disp, &ctx->call_ctx->scope);
824 IDispatch_Release(disp);
825 return hres;
826 }
827
828 /* ECMA-262 3rd Edition 12.10 */
829 static HRESULT interp_pop_scope(script_ctx_t *ctx)
830 {
831 TRACE("\n");
832
833 scope_pop(&ctx->call_ctx->scope);
834 return S_OK;
835 }
836
837 /* ECMA-262 3rd Edition 12.13 */
838 static HRESULT interp_case(script_ctx_t *ctx)
839 {
840 const unsigned arg = get_op_uint(ctx, 0);
841 jsval_t v;
842 BOOL b;
843 HRESULT hres;
844
845 TRACE("\n");
846
847 v = stack_pop(ctx);
848 hres = equal2_values(stack_top(ctx), v, &b);
849 jsval_release(v);
850 if(FAILED(hres))
851 return hres;
852
853 if(b) {
854 stack_popn(ctx, 1);
855 jmp_abs(ctx, arg);
856 }else {
857 jmp_next(ctx);
858 }
859 return S_OK;
860 }
861
862 /* ECMA-262 3rd Edition 12.13 */
863 static HRESULT interp_throw(script_ctx_t *ctx)
864 {
865 TRACE("\n");
866
867 jsval_release(ctx->ei.val);
868 ctx->ei.val = stack_pop(ctx);
869 return DISP_E_EXCEPTION;
870 }
871
872 static HRESULT interp_throw_ref(script_ctx_t *ctx)
873 {
874 const HRESULT arg = get_op_uint(ctx, 0);
875
876 TRACE("%08x\n", arg);
877
878 return throw_reference_error(ctx, arg, NULL);
879 }
880
881 static HRESULT interp_throw_type(script_ctx_t *ctx)
882 {
883 const HRESULT hres = get_op_uint(ctx, 0);
884 jsstr_t *str = get_op_str(ctx, 1);
885 const WCHAR *ptr;
886
887 TRACE("%08x %s\n", hres, debugstr_jsstr(str));
888
889 ptr = jsstr_flatten(str);
890 return ptr ? throw_type_error(ctx, hres, ptr) : E_OUTOFMEMORY;
891 }
892
893 /* ECMA-262 3rd Edition 12.14 */
894 static HRESULT interp_push_except(script_ctx_t *ctx)
895 {
896 const unsigned catch_off = get_op_uint(ctx, 0);
897 const unsigned finally_off = get_op_uint(ctx, 1);
898 call_frame_t *frame = ctx->call_ctx;
899 except_frame_t *except;
900
901 TRACE("\n");
902
903 except = heap_alloc(sizeof(*except));
904 if(!except)
905 return E_OUTOFMEMORY;
906
907 except->stack_top = ctx->stack_top;
908 except->scope = frame->scope;
909 except->catch_off = catch_off;
910 except->finally_off = finally_off;
911 except->next = frame->except_frame;
912 frame->except_frame = except;
913 return S_OK;
914 }
915
916 /* ECMA-262 3rd Edition 12.14 */
917 static HRESULT interp_pop_except(script_ctx_t *ctx)
918 {
919 const unsigned ret_off = get_op_uint(ctx, 0);
920 call_frame_t *frame = ctx->call_ctx;
921 except_frame_t *except;
922 unsigned finally_off;
923
924 TRACE("%u\n", ret_off);
925
926 except = frame->except_frame;
927 assert(except != NULL);
928
929 finally_off = except->finally_off;
930 frame->except_frame = except->next;
931 heap_free(except);
932
933 if(finally_off) {
934 HRESULT hres;
935
936 hres = stack_push(ctx, jsval_number(ret_off));
937 if(FAILED(hres))
938 return hres;
939 hres = stack_push(ctx, jsval_bool(TRUE));
940 if(FAILED(hres))
941 return hres;
942 frame->ip = finally_off;
943 }else {
944 frame->ip = ret_off;
945 }
946
947 return S_OK;
948 }
949
950 /* ECMA-262 3rd Edition 12.14 */
951 static HRESULT interp_end_finally(script_ctx_t *ctx)
952 {
953 call_frame_t *frame = ctx->call_ctx;
954 jsval_t v;
955
956 TRACE("\n");
957
958 v = stack_pop(ctx);
959 assert(is_bool(v));
960
961 if(!get_bool(v)) {
962 TRACE("passing exception\n");
963
964 ctx->ei.val = stack_pop(ctx);
965 return DISP_E_EXCEPTION;
966 }
967
968 v = stack_pop(ctx);
969 assert(is_number(v));
970 frame->ip = get_number(v);
971 return S_OK;
972 }
973
974 static HRESULT interp_enter_catch(script_ctx_t *ctx)
975 {
976 const BSTR ident = get_op_bstr(ctx, 0);
977 jsdisp_t *scope_obj;
978 jsval_t v;
979 HRESULT hres;
980
981 hres = create_dispex(ctx, NULL, NULL, &scope_obj);
982 if(FAILED(hres))
983 return hres;
984
985 v = stack_pop(ctx);
986 hres = jsdisp_propput_name(scope_obj, ident, v);
987 jsval_release(v);
988 if(SUCCEEDED(hres))
989 hres = scope_push(ctx->call_ctx->scope, scope_obj, to_disp(scope_obj), &ctx->call_ctx->scope);
990 jsdisp_release(scope_obj);
991 return hres;
992 }
993
994 /* ECMA-262 3rd Edition 13 */
995 static HRESULT interp_func(script_ctx_t *ctx)
996 {
997 unsigned func_idx = get_op_uint(ctx, 0);
998 call_frame_t *frame = ctx->call_ctx;
999 jsdisp_t *dispex;
1000 HRESULT hres;
1001
1002 TRACE("%d\n", func_idx);
1003
1004 hres = create_source_function(ctx, frame->bytecode, frame->function->funcs+func_idx,
1005 frame->scope, &dispex);
1006 if(FAILED(hres))
1007 return hres;
1008
1009 return stack_push(ctx, jsval_obj(dispex));
1010 }
1011
1012 /* ECMA-262 3rd Edition 11.2.1 */
1013 static HRESULT interp_array(script_ctx_t *ctx)
1014 {
1015 jsstr_t *name_str;
1016 const WCHAR *name;
1017 jsval_t v, namev;
1018 IDispatch *obj;
1019 DISPID id;
1020 HRESULT hres;
1021
1022 TRACE("\n");
1023
1024 namev = stack_pop(ctx);
1025
1026 hres = stack_pop_object(ctx, &obj);
1027 if(FAILED(hres)) {
1028 jsval_release(namev);
1029 return hres;
1030 }
1031
1032 hres = to_flat_string(ctx, namev, &name_str, &name);
1033 jsval_release(namev);
1034 if(FAILED(hres)) {
1035 IDispatch_Release(obj);
1036 return hres;
1037 }
1038
1039 hres = disp_get_id(ctx, obj, name, NULL, 0, &id);
1040 jsstr_release(name_str);
1041 if(SUCCEEDED(hres)) {
1042 hres = disp_propget(ctx, obj, id, &v);
1043 }else if(hres == DISP_E_UNKNOWNNAME) {
1044 v = jsval_undefined();
1045 hres = S_OK;
1046 }
1047 IDispatch_Release(obj);
1048 if(FAILED(hres))
1049 return hres;
1050
1051 return stack_push(ctx, v);
1052 }
1053
1054 /* ECMA-262 3rd Edition 11.2.1 */
1055 static HRESULT interp_member(script_ctx_t *ctx)
1056 {
1057 const BSTR arg = get_op_bstr(ctx, 0);
1058 IDispatch *obj;
1059 jsval_t v;
1060 DISPID id;
1061 HRESULT hres;
1062
1063 TRACE("\n");
1064
1065 hres = stack_pop_object(ctx, &obj);
1066 if(FAILED(hres))
1067 return hres;
1068
1069 hres = disp_get_id(ctx, obj, arg, arg, 0, &id);
1070 if(SUCCEEDED(hres)) {
1071 hres = disp_propget(ctx, obj, id, &v);
1072 }else if(hres == DISP_E_UNKNOWNNAME) {
1073 v = jsval_undefined();
1074 hres = S_OK;
1075 }
1076 IDispatch_Release(obj);
1077 if(FAILED(hres))
1078 return hres;
1079
1080 return stack_push(ctx, v);
1081 }
1082
1083 /* ECMA-262 3rd Edition 11.2.1 */
1084 static HRESULT interp_memberid(script_ctx_t *ctx)
1085 {
1086 const unsigned arg = get_op_uint(ctx, 0);
1087 jsval_t objv, namev;
1088 const WCHAR *name;
1089 jsstr_t *name_str;
1090 IDispatch *obj;
1091 exprval_t ref;
1092 DISPID id;
1093 HRESULT hres;
1094
1095 TRACE("%x\n", arg);
1096
1097 namev = stack_pop(ctx);
1098 objv = stack_pop(ctx);
1099
1100 hres = to_object(ctx, objv, &obj);
1101 jsval_release(objv);
1102 if(SUCCEEDED(hres)) {
1103 hres = to_flat_string(ctx, namev, &name_str, &name);
1104 if(FAILED(hres))
1105 IDispatch_Release(obj);
1106 }
1107 jsval_release(namev);
1108 if(FAILED(hres))
1109 return hres;
1110
1111 hres = disp_get_id(ctx, obj, name, NULL, arg, &id);
1112 jsstr_release(name_str);
1113 if(SUCCEEDED(hres)) {
1114 ref.type = EXPRVAL_IDREF;
1115 ref.u.idref.disp = obj;
1116 ref.u.idref.id = id;
1117 }else {
1118 IDispatch_Release(obj);
1119 if(hres == DISP_E_UNKNOWNNAME && !(arg & fdexNameEnsure)) {
1120 exprval_set_exception(&ref, JS_E_INVALID_PROPERTY);
1121 hres = S_OK;
1122 }else {
1123 ERR("failed %08x\n", hres);
1124 return hres;
1125 }
1126 }
1127
1128 return stack_push_exprval(ctx, &ref);
1129 }
1130
1131 /* ECMA-262 3rd Edition 11.2.1 */
1132 static HRESULT interp_refval(script_ctx_t *ctx)
1133 {
1134 exprval_t ref;
1135 jsval_t v;
1136 HRESULT hres;
1137
1138 TRACE("\n");
1139
1140 if(!stack_topn_exprval(ctx, 0, &ref))
1141 return throw_reference_error(ctx, JS_E_ILLEGAL_ASSIGN, NULL);
1142
1143 hres = exprval_propget(ctx, &ref, &v);
1144 if(FAILED(hres))
1145 return hres;
1146
1147 return stack_push(ctx, v);
1148 }
1149
1150 /* ECMA-262 3rd Edition 11.2.2 */
1151 static HRESULT interp_new(script_ctx_t *ctx)
1152 {
1153 const unsigned argc = get_op_uint(ctx, 0);
1154 call_frame_t *frame = ctx->call_ctx;
1155 jsval_t constr;
1156
1157 TRACE("%d\n", argc);
1158
1159 constr = stack_topn(ctx, argc);
1160
1161 /* NOTE: Should use to_object here */
1162
1163 if(is_null(constr))
1164 return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
1165 else if(!is_object_instance(constr))
1166 return throw_type_error(ctx, JS_E_INVALID_ACTION, NULL);
1167 else if(!get_object(constr))
1168 return throw_type_error(ctx, JS_E_INVALID_PROPERTY, NULL);
1169
1170 clear_ret(frame);
1171 return disp_call_value(ctx, get_object(constr), NULL, DISPATCH_CONSTRUCT | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
1172 argc, stack_args(ctx, argc), &frame->ret);
1173 }
1174
1175 /* ECMA-262 3rd Edition 11.2.3 */
1176 static HRESULT interp_call(script_ctx_t *ctx)
1177 {
1178 const unsigned argn = get_op_uint(ctx, 0);
1179 const int do_ret = get_op_int(ctx, 1);
1180 call_frame_t *frame = ctx->call_ctx;
1181 jsval_t obj;
1182
1183 TRACE("%d %d\n", argn, do_ret);
1184
1185 obj = stack_topn(ctx, argn);
1186 if(!is_object_instance(obj))
1187 return throw_type_error(ctx, JS_E_INVALID_PROPERTY, NULL);
1188
1189 clear_ret(frame);
1190 return disp_call_value(ctx, get_object(obj), NULL, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
1191 argn, stack_args(ctx, argn), do_ret ? &frame->ret : NULL);
1192 }
1193
1194 /* ECMA-262 3rd Edition 11.2.3 */
1195 static HRESULT interp_call_member(script_ctx_t *ctx)
1196 {
1197 const unsigned argn = get_op_uint(ctx, 0);
1198 const int do_ret = get_op_int(ctx, 1);
1199 call_frame_t *frame = ctx->call_ctx;
1200 exprval_t ref;
1201
1202 TRACE("%d %d\n", argn, do_ret);
1203
1204 if(!stack_topn_exprval(ctx, argn, &ref))
1205 return throw_type_error(ctx, ref.u.hres, NULL);
1206
1207 clear_ret(frame);
1208 return exprval_call(ctx, &ref, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
1209 argn, stack_args(ctx, argn), do_ret ? &frame->ret : NULL);
1210 }
1211
1212 /* ECMA-262 3rd Edition 11.1.1 */
1213 static HRESULT interp_this(script_ctx_t *ctx)
1214 {
1215 call_frame_t *frame = ctx->call_ctx;
1216
1217 TRACE("\n");
1218
1219 IDispatch_AddRef(frame->this_obj);
1220 return stack_push(ctx, jsval_disp(frame->this_obj));
1221 }
1222
1223 static HRESULT interp_identifier_ref(script_ctx_t *ctx, BSTR identifier, unsigned flags)
1224 {
1225 exprval_t exprval;
1226 HRESULT hres;
1227
1228 hres = identifier_eval(ctx, identifier, &exprval);
1229 if(FAILED(hres))
1230 return hres;
1231
1232 if(exprval.type == EXPRVAL_INVALID && (flags & fdexNameEnsure)) {
1233 DISPID id;
1234
1235 hres = jsdisp_get_id(ctx->global, identifier, fdexNameEnsure, &id);
1236 if(FAILED(hres))
1237 return hres;
1238
1239 exprval_set_disp_ref(&exprval, to_disp(ctx->global), id);
1240 }
1241
1242 if(exprval.type == EXPRVAL_JSVAL || exprval.type == EXPRVAL_INVALID) {
1243 WARN("invalid ref\n");
1244 exprval_release(&exprval);
1245 exprval_set_exception(&exprval, JS_E_OBJECT_EXPECTED);
1246 }
1247
1248 return stack_push_exprval(ctx, &exprval);
1249 }
1250
1251 static HRESULT identifier_value(script_ctx_t *ctx, BSTR identifier)
1252 {
1253 exprval_t exprval;
1254 jsval_t v;
1255 HRESULT hres;
1256
1257 hres = identifier_eval(ctx, identifier, &exprval);
1258 if(FAILED(hres))
1259 return hres;
1260
1261 if(exprval.type == EXPRVAL_INVALID)
1262 return throw_type_error(ctx, exprval.u.hres, identifier);
1263
1264 hres = exprval_to_value(ctx, &exprval, &v);
1265 if(FAILED(hres))
1266 return hres;
1267
1268 return stack_push(ctx, v);
1269 }
1270
1271 static HRESULT interp_local_ref(script_ctx_t *ctx)
1272 {
1273 const int arg = get_op_int(ctx, 0);
1274 const unsigned flags = get_op_uint(ctx, 1);
1275 call_frame_t *frame = ctx->call_ctx;
1276 exprval_t ref;
1277
1278 TRACE("%d\n", arg);
1279
1280 if(!frame->base_scope || !frame->base_scope->frame)
1281 return interp_identifier_ref(ctx, local_name(frame, arg), flags);
1282
1283 ref.type = EXPRVAL_STACK_REF;
1284 ref.u.off = local_off(frame, arg);
1285 return stack_push_exprval(ctx, &ref);
1286 }
1287
1288 static HRESULT interp_local(script_ctx_t *ctx)
1289 {
1290 const int arg = get_op_int(ctx, 0);
1291 call_frame_t *frame = ctx->call_ctx;
1292 jsval_t copy;
1293 HRESULT hres;
1294
1295 TRACE("%d\n", arg);
1296
1297 if(!frame->base_scope || !frame->base_scope->frame)
1298 return identifier_value(ctx, local_name(frame, arg));
1299
1300 hres = jsval_copy(ctx->stack[local_off(frame, arg)], &copy);
1301 if(FAILED(hres))
1302 return hres;
1303
1304 return stack_push(ctx, copy);
1305 }
1306
1307 /* ECMA-262 3rd Edition 10.1.4 */
1308 static HRESULT interp_ident(script_ctx_t *ctx)
1309 {
1310 const BSTR arg = get_op_bstr(ctx, 0);
1311
1312 TRACE("%s\n", debugstr_w(arg));
1313
1314 return identifier_value(ctx, arg);
1315 }
1316
1317 /* ECMA-262 3rd Edition 10.1.4 */
1318 static HRESULT interp_identid(script_ctx_t *ctx)
1319 {
1320 const BSTR arg = get_op_bstr(ctx, 0);
1321 const unsigned flags = get_op_uint(ctx, 1);
1322
1323 TRACE("%s %x\n", debugstr_w(arg), flags);
1324
1325 return interp_identifier_ref(ctx, arg, flags);
1326 }
1327
1328 /* ECMA-262 3rd Edition 7.8.1 */
1329 static HRESULT interp_null(script_ctx_t *ctx)
1330 {
1331 TRACE("\n");
1332
1333 return stack_push(ctx, jsval_null());
1334 }
1335
1336 /* ECMA-262 3rd Edition 7.8.2 */
1337 static HRESULT interp_bool(script_ctx_t *ctx)
1338 {
1339 const int arg = get_op_int(ctx, 0);
1340
1341 TRACE("%s\n", arg ? "true" : "false");
1342
1343 return stack_push(ctx, jsval_bool(arg));
1344 }
1345
1346 /* ECMA-262 3rd Edition 7.8.3 */
1347 static HRESULT interp_int(script_ctx_t *ctx)
1348 {
1349 const int arg = get_op_int(ctx, 0);
1350
1351 TRACE("%d\n", arg);
1352
1353 return stack_push(ctx, jsval_number(arg));
1354 }
1355
1356 /* ECMA-262 3rd Edition 7.8.3 */
1357 static HRESULT interp_double(script_ctx_t *ctx)
1358 {
1359 const double arg = get_op_double(ctx);
1360
1361 TRACE("%lf\n", arg);
1362
1363 return stack_push(ctx, jsval_number(arg));
1364 }
1365
1366 /* ECMA-262 3rd Edition 7.8.4 */
1367 static HRESULT interp_str(script_ctx_t *ctx)
1368 {
1369 jsstr_t *str = get_op_str(ctx, 0);
1370
1371 TRACE("%s\n", debugstr_jsstr(str));
1372
1373 return stack_push(ctx, jsval_string(jsstr_addref(str)));
1374 }
1375
1376 /* ECMA-262 3rd Edition 7.8 */
1377 static HRESULT interp_regexp(script_ctx_t *ctx)
1378 {
1379 jsstr_t *source = get_op_str(ctx, 0);
1380 const unsigned flags = get_op_uint(ctx, 1);
1381 jsdisp_t *regexp;
1382 HRESULT hres;
1383
1384 TRACE("%s %x\n", debugstr_jsstr(source), flags);
1385
1386 hres = create_regexp(ctx, source, flags, &regexp);
1387 if(FAILED(hres))
1388 return hres;
1389
1390 return stack_push(ctx, jsval_obj(regexp));
1391 }
1392
1393 /* ECMA-262 3rd Edition 11.1.4 */
1394 static HRESULT interp_carray(script_ctx_t *ctx)
1395 {
1396 const unsigned arg = get_op_uint(ctx, 0);
1397 jsdisp_t *array;
1398 jsval_t val;
1399 unsigned i;
1400 HRESULT hres;
1401
1402 TRACE("%u\n", arg);
1403
1404 hres = create_array(ctx, arg, &array);
1405 if(FAILED(hres))
1406 return hres;
1407
1408 i = arg;
1409 while(i--) {
1410 val = stack_pop(ctx);
1411 hres = jsdisp_propput_idx(array, i, val);
1412 jsval_release(val);
1413 if(FAILED(hres)) {
1414 jsdisp_release(array);
1415 return hres;
1416 }
1417 }
1418
1419 return stack_push(ctx, jsval_obj(array));
1420 }
1421
1422 /* ECMA-262 3rd Edition 11.1.5 */
1423 static HRESULT interp_new_obj(script_ctx_t *ctx)
1424 {
1425 jsdisp_t *obj;
1426 HRESULT hres;
1427
1428 TRACE("\n");
1429
1430 hres = create_object(ctx, NULL, &obj);
1431 if(FAILED(hres))
1432 return hres;
1433
1434 return stack_push(ctx, jsval_obj(obj));
1435 }
1436
1437 /* ECMA-262 3rd Edition 11.1.5 */
1438 static HRESULT interp_obj_prop(script_ctx_t *ctx)
1439 {
1440 const BSTR name = get_op_bstr(ctx, 0);
1441 jsdisp_t *obj;
1442 jsval_t val;
1443 HRESULT hres;
1444
1445 TRACE("%s\n", debugstr_w(name));
1446
1447 val = stack_pop(ctx);
1448
1449 assert(is_object_instance(stack_top(ctx)));
1450 obj = as_jsdisp(get_object(stack_top(ctx)));
1451
1452 hres = jsdisp_propput_name(obj, name, val);
1453 jsval_release(val);
1454 return hres;
1455 }
1456
1457 /* ECMA-262 3rd Edition 11.11 */
1458 static HRESULT interp_cnd_nz(script_ctx_t *ctx)
1459 {
1460 const unsigned arg = get_op_uint(ctx, 0);
1461 BOOL b;
1462 HRESULT hres;
1463
1464 TRACE("\n");
1465
1466 hres = to_boolean(stack_top(ctx), &b);
1467 if(FAILED(hres))
1468 return hres;
1469
1470 if(b) {
1471 jmp_abs(ctx, arg);
1472 }else {
1473 stack_popn(ctx, 1);
1474 jmp_next(ctx);
1475 }
1476 return S_OK;
1477 }
1478
1479 /* ECMA-262 3rd Edition 11.11 */
1480 static HRESULT interp_cnd_z(script_ctx_t *ctx)
1481 {
1482 const unsigned arg = get_op_uint(ctx, 0);
1483 BOOL b;
1484 HRESULT hres;
1485
1486 TRACE("\n");
1487
1488 hres = to_boolean(stack_top(ctx), &b);
1489 if(FAILED(hres))
1490 return hres;
1491
1492 if(b) {
1493 stack_popn(ctx, 1);
1494 jmp_next(ctx);
1495 }else {
1496 jmp_abs(ctx, arg);
1497 }
1498 return S_OK;
1499 }
1500
1501 /* ECMA-262 3rd Edition 11.10 */
1502 static HRESULT interp_or(script_ctx_t *ctx)
1503 {
1504 INT l, r;
1505 HRESULT hres;
1506
1507 TRACE("\n");
1508
1509 hres = stack_pop_int(ctx, &r);
1510 if(FAILED(hres))
1511 return hres;
1512
1513 hres = stack_pop_int(ctx, &l);
1514 if(FAILED(hres))
1515 return hres;
1516
1517 return stack_push(ctx, jsval_number(l|r));
1518 }
1519
1520 /* ECMA-262 3rd Edition 11.10 */
1521 static HRESULT interp_xor(script_ctx_t *ctx)
1522 {
1523 INT l, r;
1524 HRESULT hres;
1525
1526 TRACE("\n");
1527
1528 hres = stack_pop_int(ctx, &r);
1529 if(FAILED(hres))
1530 return hres;
1531
1532 hres = stack_pop_int(ctx, &l);
1533 if(FAILED(hres))
1534 return hres;
1535
1536 return stack_push(ctx, jsval_number(l^r));
1537 }
1538
1539 /* ECMA-262 3rd Edition 11.10 */
1540 static HRESULT interp_and(script_ctx_t *ctx)
1541 {
1542 INT l, r;
1543 HRESULT hres;
1544
1545 TRACE("\n");
1546
1547 hres = stack_pop_int(ctx, &r);
1548 if(FAILED(hres))
1549 return hres;
1550
1551 hres = stack_pop_int(ctx, &l);
1552 if(FAILED(hres))
1553 return hres;
1554
1555 return stack_push(ctx, jsval_number(l&r));
1556 }
1557
1558 /* ECMA-262 3rd Edition 11.8.6 */
1559 static HRESULT interp_instanceof(script_ctx_t *ctx)
1560 {
1561 jsdisp_t *obj, *iter, *tmp = NULL;
1562 jsval_t prot, v;
1563 BOOL ret = FALSE;
1564 HRESULT hres;
1565
1566 static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0};
1567
1568 v = stack_pop(ctx);
1569 if(!is_object_instance(v) || !get_object(v)) {
1570 jsval_release(v);
1571 return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
1572 }
1573
1574 obj = iface_to_jsdisp(get_object(v));
1575 IDispatch_Release(get_object(v));
1576 if(!obj) {
1577 FIXME("non-jsdisp objects not supported\n");
1578 return E_FAIL;
1579 }
1580
1581 if(is_class(obj, JSCLASS_FUNCTION)) {
1582 hres = jsdisp_propget_name(obj, prototypeW, &prot);
1583 }else {
1584 hres = throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
1585 }
1586 jsdisp_release(obj);
1587 if(FAILED(hres))
1588 return hres;
1589
1590 v = stack_pop(ctx);
1591
1592 if(is_object_instance(prot)) {
1593 if(is_object_instance(v))
1594 tmp = iface_to_jsdisp(get_object(v));
1595 for(iter = tmp; !ret && iter; iter = iter->prototype) {
1596 hres = disp_cmp(get_object(prot), to_disp(iter), &ret);
1597 if(FAILED(hres))
1598 break;
1599 }
1600
1601 if(tmp)
1602 jsdisp_release(tmp);
1603 }else {
1604 FIXME("prototype is not an object\n");
1605 hres = E_FAIL;
1606 }
1607
1608 jsval_release(prot);
1609 jsval_release(v);
1610 if(FAILED(hres))
1611 return hres;
1612
1613 return stack_push(ctx, jsval_bool(ret));
1614 }
1615
1616 /* ECMA-262 3rd Edition 11.8.7 */
1617 static HRESULT interp_in(script_ctx_t *ctx)
1618 {
1619 const WCHAR *str;
1620 jsstr_t *jsstr;
1621 jsval_t obj, v;
1622 DISPID id = 0;
1623 BOOL ret;
1624 HRESULT hres;
1625
1626 TRACE("\n");
1627
1628 obj = stack_pop(ctx);
1629 if(!is_object_instance(obj) || !get_object(obj)) {
1630 jsval_release(obj);
1631 return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
1632 }
1633
1634 v = stack_pop(ctx);
1635 hres = to_flat_string(ctx, v, &jsstr, &str);
1636 jsval_release(v);
1637 if(FAILED(hres)) {
1638 IDispatch_Release(get_object(obj));
1639 return hres;
1640 }
1641
1642 hres = disp_get_id(ctx, get_object(obj), str, NULL, 0, &id);
1643 IDispatch_Release(get_object(obj));
1644 jsstr_release(jsstr);
1645 if(SUCCEEDED(hres))
1646 ret = TRUE;
1647 else if(hres == DISP_E_UNKNOWNNAME)
1648 ret = FALSE;
1649 else
1650 return hres;
1651
1652 return stack_push(ctx, jsval_bool(ret));
1653 }
1654
1655 /* ECMA-262 3rd Edition 11.6.1 */
1656 static HRESULT add_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, jsval_t *ret)
1657 {
1658 jsval_t r, l;
1659 HRESULT hres;
1660
1661 hres = to_primitive(ctx, lval, &l, NO_HINT);
1662 if(FAILED(hres))
1663 return hres;
1664
1665 hres = to_primitive(ctx, rval, &r, NO_HINT);
1666 if(FAILED(hres)) {
1667 jsval_release(l);
1668 return hres;
1669 }
1670
1671 if(is_string(l) || is_string(r)) {
1672 jsstr_t *lstr, *rstr = NULL;
1673
1674 hres = to_string(ctx, l, &lstr);
1675 if(SUCCEEDED(hres))
1676 hres = to_string(ctx, r, &rstr);
1677
1678 if(SUCCEEDED(hres)) {
1679 jsstr_t *ret_str;
1680
1681 ret_str = jsstr_concat(lstr, rstr);
1682 if(ret_str)
1683 *ret = jsval_string(ret_str);
1684 else
1685 hres = E_OUTOFMEMORY;
1686 }
1687
1688 jsstr_release(lstr);
1689 if(rstr)
1690 jsstr_release(rstr);
1691 }else {
1692 double nl, nr;
1693
1694 hres = to_number(ctx, l, &nl);
1695 if(SUCCEEDED(hres)) {
1696 hres = to_number(ctx, r, &nr);
1697 if(SUCCEEDED(hres))
1698 *ret = jsval_number(nl+nr);
1699 }
1700 }
1701
1702 jsval_release(r);
1703 jsval_release(l);
1704 return hres;
1705 }
1706
1707 /* ECMA-262 3rd Edition 11.6.1 */
1708 static HRESULT interp_add(script_ctx_t *ctx)
1709 {
1710 jsval_t l, r, ret;
1711 HRESULT hres;
1712
1713 r = stack_pop(ctx);
1714 l = stack_pop(ctx);
1715
1716 TRACE("%s + %s\n", debugstr_jsval(l), debugstr_jsval(r));
1717
1718 hres = add_eval(ctx, l, r, &ret);
1719 jsval_release(l);
1720 jsval_release(r);
1721 if(FAILED(hres))
1722 return hres;
1723
1724 return stack_push(ctx, ret);
1725 }
1726
1727 /* ECMA-262 3rd Edition 11.6.2 */
1728 static HRESULT interp_sub(script_ctx_t *ctx)
1729 {
1730 double l, r;
1731 HRESULT hres;
1732
1733 TRACE("\n");
1734
1735 hres = stack_pop_number(ctx, &r);
1736 if(FAILED(hres))
1737 return hres;
1738
1739 hres = stack_pop_number(ctx, &l);
1740 if(FAILED(hres))
1741 return hres;
1742
1743 return stack_push(ctx, jsval_number(l-r));
1744 }
1745
1746 /* ECMA-262 3rd Edition 11.5.1 */
1747 static HRESULT interp_mul(script_ctx_t *ctx)
1748 {
1749 double l, r;
1750 HRESULT hres;
1751
1752 TRACE("\n");
1753
1754 hres = stack_pop_number(ctx, &r);
1755 if(FAILED(hres))
1756 return hres;
1757
1758 hres = stack_pop_number(ctx, &l);
1759 if(FAILED(hres))
1760 return hres;
1761
1762 return stack_push(ctx, jsval_number(l*r));
1763 }
1764
1765 /* ECMA-262 3rd Edition 11.5.2 */
1766 static HRESULT interp_div(script_ctx_t *ctx)
1767 {
1768 double l, r;
1769 HRESULT hres;
1770
1771 TRACE("\n");
1772
1773 hres = stack_pop_number(ctx, &r);
1774 if(FAILED(hres))
1775 return hres;
1776
1777 hres = stack_pop_number(ctx, &l);
1778 if(FAILED(hres))
1779 return hres;
1780
1781 return stack_push(ctx, jsval_number(l/r));
1782 }
1783
1784 /* ECMA-262 3rd Edition 11.5.3 */
1785 static HRESULT interp_mod(script_ctx_t *ctx)
1786 {
1787 double l, r;
1788 HRESULT hres;
1789
1790 TRACE("\n");
1791
1792 hres = stack_pop_number(ctx, &r);
1793 if(FAILED(hres))
1794 return hres;
1795
1796 hres = stack_pop_number(ctx, &l);
1797 if(FAILED(hres))
1798 return hres;
1799
1800 return stack_push(ctx, jsval_number(fmod(l, r)));
1801 }
1802
1803 /* ECMA-262 3rd Edition 11.4.2 */
1804 static HRESULT interp_delete(script_ctx_t *ctx)
1805 {
1806 jsval_t objv, namev;
1807 IDispatch *obj;
1808 jsstr_t *name;
1809 BOOL ret;
1810 HRESULT hres;
1811
1812 TRACE("\n");
1813
1814 namev = stack_pop(ctx);
1815 objv = stack_pop(ctx);
1816
1817 hres = to_object(ctx, objv, &obj);
1818 jsval_release(objv);
1819 if(FAILED(hres)) {
1820 jsval_release(namev);
1821 return hres;
1822 }
1823
1824 hres = to_string(ctx, namev, &name);
1825 jsval_release(namev);
1826 if(FAILED(hres)) {
1827 IDispatch_Release(obj);
1828 return hres;
1829 }
1830
1831 hres = disp_delete_name(ctx, obj, name, &ret);
1832 IDispatch_Release(obj);
1833 jsstr_release(name);
1834 if(FAILED(hres))
1835 return hres;
1836
1837 return stack_push(ctx, jsval_bool(ret));
1838 }
1839
1840 /* ECMA-262 3rd Edition 11.4.2 */
1841 static HRESULT interp_delete_ident(script_ctx_t *ctx)
1842 {
1843 const BSTR arg = get_op_bstr(ctx, 0);
1844 exprval_t exprval;
1845 BOOL ret;
1846 HRESULT hres;
1847
1848 TRACE("%s\n", debugstr_w(arg));
1849
1850 hres = identifier_eval(ctx, arg, &exprval);
1851 if(FAILED(hres))
1852 return hres;
1853
1854 switch(exprval.type) {
1855 case EXPRVAL_STACK_REF:
1856 ret = FALSE;
1857 break;
1858 case EXPRVAL_IDREF:
1859 hres = disp_delete(exprval.u.idref.disp, exprval.u.idref.id, &ret);
1860 IDispatch_Release(exprval.u.idref.disp);
1861 if(FAILED(hres))
1862 return hres;
1863 break;
1864 case EXPRVAL_INVALID:
1865 ret = TRUE;
1866 break;
1867 default:
1868 FIXME("Unsupported exprval\n");
1869 exprval_release(&exprval);
1870 return E_NOTIMPL;
1871 }
1872
1873
1874 return stack_push(ctx, jsval_bool(ret));
1875 }
1876
1877 /* ECMA-262 3rd Edition 11.4.2 */
1878 static HRESULT interp_void(script_ctx_t *ctx)
1879 {
1880 TRACE("\n");
1881
1882 stack_popn(ctx, 1);
1883 return stack_push(ctx, jsval_undefined());
1884 }
1885
1886 /* ECMA-262 3rd Edition 11.4.3 */
1887 static HRESULT typeof_string(jsval_t v, const WCHAR **ret)
1888 {
1889 switch(jsval_type(v)) {
1890 case JSV_UNDEFINED:
1891 *ret = undefinedW;
1892 break;
1893 case JSV_NULL:
1894 *ret = objectW;
1895 break;
1896 case JSV_OBJECT: {
1897 jsdisp_t *dispex;
1898
1899 if(get_object(v) && (dispex = iface_to_jsdisp(get_object(v)))) {
1900 *ret = is_class(dispex, JSCLASS_FUNCTION) ? functionW : objectW;
1901 jsdisp_release(dispex);
1902 }else {
1903 *ret = objectW;
1904 }
1905 break;
1906 }
1907 case JSV_STRING:
1908 *ret = stringW;
1909 break;
1910 case JSV_NUMBER:
1911 *ret = numberW;
1912 break;
1913 case JSV_BOOL:
1914 *ret = booleanW;
1915 break;
1916 case JSV_VARIANT:
1917 FIXME("unhandled variant %s\n", debugstr_variant(get_variant(v)));
1918 return E_NOTIMPL;
1919 }
1920
1921 return S_OK;
1922 }
1923
1924 /* ECMA-262 3rd Edition 11.4.3 */
1925 static HRESULT interp_typeofid(script_ctx_t *ctx)
1926 {
1927 const WCHAR *ret;
1928 exprval_t ref;
1929 jsval_t v;
1930 HRESULT hres;
1931
1932 TRACE("\n");
1933
1934 if(!stack_pop_exprval(ctx, &ref))
1935 return stack_push(ctx, jsval_string(jsstr_undefined()));
1936
1937 hres = exprval_propget(ctx, &ref, &v);
1938 exprval_release(&ref);
1939 if(FAILED(hres))
1940 return stack_push_string(ctx, unknownW);
1941
1942 hres = typeof_string(v, &ret);
1943 jsval_release(v);
1944 if(FAILED(hres))
1945 return hres;
1946
1947 return stack_push_string(ctx, ret);
1948 }
1949
1950 /* ECMA-262 3rd Edition 11.4.3 */
1951 static HRESULT interp_typeofident(script_ctx_t *ctx)
1952 {
1953 const BSTR arg = get_op_bstr(ctx, 0);
1954 exprval_t exprval;
1955 const WCHAR *ret;
1956 jsval_t v;
1957 HRESULT hres;
1958
1959 TRACE("%s\n", debugstr_w(arg));
1960
1961 hres = identifier_eval(ctx, arg, &exprval);
1962 if(FAILED(hres))
1963 return hres;
1964
1965 if(exprval.type == EXPRVAL_INVALID)
1966 return stack_push(ctx, jsval_string(jsstr_undefined()));
1967
1968 hres = exprval_to_value(ctx, &exprval, &v);
1969 if(FAILED(hres))
1970 return hres;
1971
1972 hres = typeof_string(v, &ret);
1973 jsval_release(v);
1974 if(FAILED(hres))
1975 return hres;
1976
1977 return stack_push_string(ctx, ret);
1978 }
1979
1980 /* ECMA-262 3rd Edition 11.4.3 */
1981 static HRESULT interp_typeof(script_ctx_t *ctx)
1982 {
1983 const WCHAR *ret;
1984 jsval_t v;
1985 HRESULT hres;
1986
1987 TRACE("\n");
1988
1989 v = stack_pop(ctx);
1990 hres = typeof_string(v, &ret);
1991 jsval_release(v);
1992 if(FAILED(hres))
1993 return hres;
1994
1995 return stack_push_string(ctx, ret);
1996 }
1997
1998 /* ECMA-262 3rd Edition 11.4.7 */
1999 static HRESULT interp_minus(script_ctx_t *ctx)
2000 {
2001 double n;
2002 HRESULT hres;
2003
2004 TRACE("\n");
2005
2006 hres = stack_pop_number(ctx, &n);
2007 if(FAILED(hres))
2008 return hres;
2009
2010 return stack_push(ctx, jsval_number(-n));
2011 }
2012
2013 /* ECMA-262 3rd Edition 11.4.6 */
2014 static HRESULT interp_tonum(script_ctx_t *ctx)
2015 {
2016 jsval_t v;
2017 double n;
2018 HRESULT hres;
2019
2020 TRACE("\n");
2021
2022 v = stack_pop(ctx);
2023 hres = to_number(ctx, v, &n);
2024 jsval_release(v);
2025 if(FAILED(hres))
2026 return hres;
2027
2028 return stack_push(ctx, jsval_number(n));
2029 }
2030
2031 /* ECMA-262 3rd Edition 11.3.1 */
2032 static HRESULT interp_postinc(script_ctx_t *ctx)
2033 {
2034 const int arg = get_op_int(ctx, 0);
2035 exprval_t ref;
2036 jsval_t v;
2037 HRESULT hres;
2038
2039 TRACE("%d\n", arg);
2040
2041 if(!stack_pop_exprval(ctx, &ref))
2042 return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
2043
2044 hres = exprval_propget(ctx, &ref, &v);
2045 if(SUCCEEDED(hres)) {
2046 double n;
2047
2048 hres = to_number(ctx, v, &n);
2049 if(SUCCEEDED(hres))
2050 hres = exprval_propput(ctx, &ref, jsval_number(n+(double)arg));
2051 if(FAILED(hres))
2052 jsval_release(v);
2053 }
2054 exprval_release(&ref);
2055 if(FAILED(hres))
2056 return hres;
2057
2058 return stack_push(ctx, v);
2059 }
2060
2061 /* ECMA-262 3rd Edition 11.4.4, 11.4.5 */
2062 static HRESULT interp_preinc(script_ctx_t *ctx)
2063 {
2064 const int arg = get_op_int(ctx, 0);
2065 exprval_t ref;
2066 double ret;
2067 jsval_t v;
2068 HRESULT hres;
2069
2070 TRACE("%d\n", arg);
2071
2072 if(!stack_pop_exprval(ctx, &ref))
2073 return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
2074
2075 hres = exprval_propget(ctx, &ref, &v);
2076 if(SUCCEEDED(hres)) {
2077 double n;
2078
2079 hres = to_number(ctx, v, &n);
2080 jsval_release(v);
2081 if(SUCCEEDED(hres)) {
2082 ret = n+(double)arg;
2083 hres = exprval_propput(ctx, &ref, jsval_number(ret));
2084 }
2085 }
2086 exprval_release(&ref);
2087 if(FAILED(hres))
2088 return hres;
2089
2090 return stack_push(ctx, jsval_number(ret));
2091 }
2092
2093 /* ECMA-262 3rd Edition 11.9.3 */
2094 static HRESULT equal_values(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL *ret)
2095 {
2096 if(jsval_type(lval) == jsval_type(rval) || (is_number(lval) && is_number(rval)))
2097 return equal2_values(lval, rval, ret);
2098
2099 /* FIXME: NULL disps should be handled in more general way */
2100 if(is_object_instance(lval) && !get_object(lval))
2101 return equal_values(ctx, jsval_null(), rval, ret);
2102 if(is_object_instance(rval) && !get_object(rval))
2103 return equal_values(ctx, lval, jsval_null(), ret);
2104
2105 if((is_null(lval) && is_undefined(rval)) || (is_undefined(lval) && is_null(rval))) {
2106 *ret = TRUE;
2107 return S_OK;
2108 }
2109
2110 if(is_string(lval) && is_number(rval)) {
2111 double n;
2112 HRESULT hres;
2113
2114 hres = to_number(ctx, lval, &n);
2115 if(FAILED(hres))
2116 return hres;
2117
2118 /* FIXME: optimize */
2119 return equal_values(ctx, jsval_number(n), rval, ret);
2120 }
2121
2122 if(is_string(rval) && is_number(lval)) {
2123 double n;
2124 HRESULT hres;
2125
2126 hres = to_number(ctx, rval, &n);
2127 if(FAILED(hres))
2128 return hres;
2129
2130 /* FIXME: optimize */
2131 return equal_values(ctx, lval, jsval_number(n), ret);
2132 }
2133
2134 if(is_bool(rval))
2135 return equal_values(ctx, lval, jsval_number(get_bool(rval) ? 1 : 0), ret);
2136
2137 if(is_bool(lval))
2138 return equal_values(ctx, jsval_number(get_bool(lval) ? 1 : 0), rval, ret);
2139
2140
2141 if(is_object_instance(rval) && (is_string(lval) || is_number(lval))) {
2142 jsval_t prim;
2143 HRESULT hres;
2144
2145 hres = to_primitive(ctx, rval, &prim, NO_HINT);
2146 if(FAILED(hres))
2147 return hres;
2148
2149 hres = equal_values(ctx, lval, prim, ret);
2150 jsval_release(prim);
2151 return hres;
2152 }
2153
2154
2155 if(is_object_instance(lval) && (is_string(rval) || is_number(rval))) {
2156 jsval_t prim;
2157 HRESULT hres;
2158
2159 hres = to_primitive(ctx, lval, &prim, NO_HINT);
2160 if(FAILED(hres))
2161 return hres;
2162
2163 hres = equal_values(ctx, prim, rval, ret);
2164 jsval_release(prim);
2165 return hres;
2166 }
2167
2168
2169 *ret = FALSE;
2170 return S_OK;
2171 }
2172
2173 /* ECMA-262 3rd Edition 11.9.1 */
2174 static HRESULT interp_eq(script_ctx_t *ctx)
2175 {
2176 jsval_t l, r;
2177 BOOL b;
2178 HRESULT hres;
2179
2180 r = stack_pop(ctx);
2181 l = stack_pop(ctx);
2182
2183 TRACE("%s == %s\n", debugstr_jsval(l), debugstr_jsval(r));
2184
2185 hres = equal_values(ctx, l, r, &b);
2186 jsval_release(l);
2187 jsval_release(r);
2188 if(FAILED(hres))
2189 return hres;
2190
2191 return stack_push(ctx, jsval_bool(b));
2192 }
2193
2194 /* ECMA-262 3rd Edition 11.9.2 */
2195 static HRESULT interp_neq(script_ctx_t *ctx)
2196 {
2197 jsval_t l, r;
2198 BOOL b;
2199 HRESULT hres;
2200
2201 r = stack_pop(ctx);
2202 l = stack_pop(ctx);
2203
2204 TRACE("%s != %s\n", debugstr_jsval(l), debugstr_jsval(r));
2205
2206 hres = equal_values(ctx, l, r, &b);
2207 jsval_release(l);
2208 jsval_release(r);
2209 if(FAILED(hres))
2210 return hres;
2211
2212 return stack_push(ctx, jsval_bool(!b));
2213 }
2214
2215 /* ECMA-262 3rd Edition 11.9.4 */
2216 static HRESULT interp_eq2(script_ctx_t *ctx)
2217 {
2218 jsval_t l, r;
2219 BOOL b;
2220 HRESULT hres;
2221
2222 r = stack_pop(ctx);
2223 l = stack_pop(ctx);
2224
2225 TRACE("%s === %s\n", debugstr_jsval(l), debugstr_jsval(r));
2226
2227 hres = equal2_values(r, l, &b);
2228 jsval_release(l);
2229 jsval_release(r);
2230 if(FAILED(hres))
2231 return hres;
2232
2233 return stack_push(ctx, jsval_bool(b));
2234 }
2235
2236 /* ECMA-262 3rd Edition 11.9.5 */
2237 static HRESULT interp_neq2(script_ctx_t *ctx)
2238 {
2239 jsval_t l, r;
2240 BOOL b;
2241 HRESULT hres;
2242
2243 TRACE("\n");
2244
2245 r = stack_pop(ctx);
2246 l = stack_pop(ctx);
2247
2248 hres = equal2_values(r, l, &b);
2249 jsval_release(l);
2250 jsval_release(r);
2251 if(FAILED(hres))
2252 return hres;
2253
2254 return stack_push(ctx, jsval_bool(!b));
2255 }
2256
2257 /* ECMA-262 3rd Edition 11.8.5 */
2258 static HRESULT less_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL greater, BOOL *ret)
2259 {
2260 double ln, rn;
2261 jsval_t l, r;
2262 HRESULT hres;
2263
2264 hres = to_primitive(ctx, lval, &l, NO_HINT);
2265 if(FAILED(hres))
2266 return hres;
2267
2268 hres = to_primitive(ctx, rval, &r, NO_HINT);
2269 if(FAILED(hres)) {
2270 jsval_release(l);
2271 return hres;
2272 }
2273
2274 if(is_string(l) && is_string(r)) {
2275 *ret = (jsstr_cmp(get_string(l), get_string(r)) < 0) ^ greater;
2276 jsstr_release(get_string(l));
2277 jsstr_release(get_string(r));
2278 return S_OK;
2279 }
2280
2281 hres = to_number(ctx, l, &ln);
2282 jsval_release(l);
2283 if(SUCCEEDED(hres))
2284 hres = to_number(ctx, r, &rn);
2285 jsval_release(r);
2286 if(FAILED(hres))
2287 return hres;
2288
2289 *ret = !isnan(ln) && !isnan(rn) && ((ln < rn) ^ greater);
2290 return S_OK;
2291 }
2292
2293 /* ECMA-262 3rd Edition 11.8.1 */
2294 static HRESULT interp_lt(script_ctx_t *ctx)
2295 {
2296 jsval_t l, r;
2297 BOOL b;
2298 HRESULT hres;
2299
2300 r = stack_pop(ctx);
2301 l = stack_pop(ctx);
2302
2303 TRACE("%s < %s\n", debugstr_jsval(l), debugstr_jsval(r));
2304
2305 hres = less_eval(ctx, l, r, FALSE, &b);
2306 jsval_release(l);
2307 jsval_release(r);
2308 if(FAILED(hres))
2309 return hres;
2310
2311 return stack_push(ctx, jsval_bool(b));
2312 }
2313
2314 /* ECMA-262 3rd Edition 11.8.1 */
2315 static HRESULT interp_lteq(script_ctx_t *ctx)
2316 {
2317 jsval_t l, r;
2318 BOOL b;
2319 HRESULT hres;
2320
2321 r = stack_pop(ctx);
2322 l = stack_pop(ctx);
2323
2324 TRACE("%s <= %s\n", debugstr_jsval(l), debugstr_jsval(r));
2325
2326 hres = less_eval(ctx, r, l, TRUE, &b);
2327 jsval_release(l);
2328 jsval_release(r);
2329 if(FAILED(hres))
2330 return hres;
2331
2332 return stack_push(ctx, jsval_bool(b));
2333 }
2334
2335 /* ECMA-262 3rd Edition 11.8.2 */
2336 static HRESULT interp_gt(script_ctx_t *ctx)
2337 {
2338 jsval_t l, r;
2339 BOOL b;
2340 HRESULT hres;
2341
2342 r = stack_pop(ctx);
2343 l = stack_pop(ctx);
2344
2345 TRACE("%s > %s\n", debugstr_jsval(l), debugstr_jsval(r));
2346
2347 hres = less_eval(ctx, r, l, FALSE, &b);
2348 jsval_release(l);
2349 jsval_release(r);
2350 if(FAILED(hres))
2351 return hres;
2352
2353 return stack_push(ctx, jsval_bool(b));
2354 }
2355
2356 /* ECMA-262 3rd Edition 11.8.4 */
2357 static HRESULT interp_gteq(script_ctx_t *ctx)
2358 {
2359 jsval_t l, r;
2360 BOOL b;
2361 HRESULT hres;
2362
2363 r = stack_pop(ctx);
2364 l = stack_pop(ctx);
2365
2366 TRACE("%s >= %s\n", debugstr_jsval(l), debugstr_jsval(r));
2367
2368 hres = less_eval(ctx, l, r, TRUE, &b);
2369 jsval_release(l);
2370 jsval_release(r);
2371 if(FAILED(hres))
2372 return hres;
2373
2374 return stack_push(ctx, jsval_bool(b));
2375 }
2376
2377 /* ECMA-262 3rd Edition 11.4.8 */
2378 static HRESULT interp_bneg(script_ctx_t *ctx)
2379 {
2380 jsval_t v;
2381 INT i;
2382 HRESULT hres;
2383
2384 TRACE("\n");
2385
2386 v = stack_pop(ctx);
2387 hres = to_int32(ctx, v, &i);
2388 jsval_release(v);
2389 if(FAILED(hres))
2390 return hres;
2391
2392 return stack_push(ctx, jsval_number(~i));
2393 }
2394
2395 /* ECMA-262 3rd Edition 11.4.9 */
2396 static HRESULT interp_neg(script_ctx_t *ctx)
2397 {
2398 jsval_t v;
2399 BOOL b;
2400 HRESULT hres;
2401
2402 TRACE("\n");
2403
2404 v = stack_pop(ctx);
2405 hres = to_boolean(v, &b);
2406 jsval_release(v);
2407 if(FAILED(hres))
2408 return hres;
2409
2410 return stack_push(ctx, jsval_bool(!b));
2411 }
2412
2413 /* ECMA-262 3rd Edition 11.7.1 */
2414 static HRESULT interp_lshift(script_ctx_t *ctx)
2415 {
2416 DWORD r;
2417 INT l;
2418 HRESULT hres;
2419
2420 hres = stack_pop_uint(ctx, &r);
2421 if(FAILED(hres))
2422 return hres;
2423
2424 hres = stack_pop_int(ctx, &l);
2425 if(FAILED(hres))
2426 return hres;
2427
2428 return stack_push(ctx, jsval_number(l << (r&0x1f)));
2429 }
2430
2431 /* ECMA-262 3rd Edition 11.7.2 */
2432 static HRESULT interp_rshift(script_ctx_t *ctx)
2433 {
2434 DWORD r;
2435 INT l;
2436 HRESULT hres;
2437
2438 hres = stack_pop_uint(ctx, &r);
2439 if(FAILED(hres))
2440 return hres;
2441
2442 hres = stack_pop_int(ctx, &l);
2443 if(FAILED(hres))
2444 return hres;
2445
2446 return stack_push(ctx, jsval_number(l >> (r&0x1f)));
2447 }
2448
2449 /* ECMA-262 3rd Edition 11.7.3 */
2450 static HRESULT interp_rshift2(script_ctx_t *ctx)
2451 {
2452 DWORD r, l;
2453 HRESULT hres;
2454
2455 hres = stack_pop_uint(ctx, &r);
2456 if(FAILED(hres))
2457 return hres;
2458
2459 hres = stack_pop_uint(ctx, &l);
2460 if(FAILED(hres))
2461 return hres;
2462
2463 return stack_push(ctx, jsval_number(l >> (r&0x1f)));
2464 }
2465
2466 /* ECMA-262 3rd Edition 11.13.1 */
2467 static HRESULT interp_assign(script_ctx_t *ctx)
2468 {
2469 exprval_t ref;
2470 jsval_t v;
2471 HRESULT hres;
2472
2473 TRACE("\n");
2474
2475 v = stack_pop(ctx);
2476
2477 if(!stack_pop_exprval(ctx, &ref)) {
2478 jsval_release(v);
2479 return throw_reference_error(ctx, JS_E_ILLEGAL_ASSIGN, NULL);
2480 }
2481
2482 hres = exprval_propput(ctx, &ref, v);
2483 exprval_release(&ref);
2484 if(FAILED(hres)) {
2485 jsval_release(v);
2486 return hres;
2487 }
2488
2489 return stack_push(ctx, v);
2490 }
2491
2492 /* JScript extension */
2493 static HRESULT interp_assign_call(script_ctx_t *ctx)
2494 {
2495 const unsigned argc = get_op_uint(ctx, 0);
2496 exprval_t ref;
2497 jsval_t v;
2498 HRESULT hres;
2499
2500 TRACE("%u\n", argc);
2501
2502 if(!stack_topn_exprval(ctx, argc+1, &ref))
2503 return throw_reference_error(ctx, JS_E_ILLEGAL_ASSIGN, NULL);
2504
2505 hres = exprval_call(ctx, &ref, DISPATCH_PROPERTYPUT, argc+1, stack_args(ctx, argc+1), NULL);
2506 if(FAILED(hres))
2507 return hres;
2508
2509 v = stack_pop(ctx);
2510 stack_popn(ctx, argc+2);
2511 return stack_push(ctx, v);
2512 }
2513
2514 static HRESULT interp_undefined(script_ctx_t *ctx)
2515 {
2516 TRACE("\n");
2517
2518 return stack_push(ctx, jsval_undefined());
2519 }
2520
2521 static HRESULT interp_jmp(script_ctx_t *ctx)
2522 {
2523 const unsigned arg = get_op_uint(ctx, 0);
2524
2525 TRACE("%u\n", arg);
2526
2527 jmp_abs(ctx, arg);
2528 return S_OK;
2529 }
2530
2531 static HRESULT interp_jmp_z(script_ctx_t *ctx)
2532 {
2533 const unsigned arg = get_op_uint(ctx, 0);
2534 BOOL b;
2535 jsval_t v;
2536 HRESULT hres;
2537
2538 TRACE("\n");
2539
2540 v = stack_pop(ctx);
2541 hres = to_boolean(v, &b);
2542 jsval_release(v);
2543 if(FAILED(hres))
2544 return hres;
2545
2546 if(b)
2547 jmp_next(ctx);
2548 else
2549 jmp_abs(ctx, arg);
2550 return S_OK;
2551 }
2552
2553 static HRESULT interp_pop(script_ctx_t *ctx)
2554 {
2555 const unsigned arg = get_op_uint(ctx, 0);
2556
2557 TRACE("%u\n", arg);
2558
2559 stack_popn(ctx, arg);
2560 return S_OK;
2561 }
2562
2563 static HRESULT interp_ret(script_ctx_t *ctx)
2564 {
2565 const unsigned clear_ret = get_op_uint(ctx, 0);
2566 call_frame_t *frame = ctx->call_ctx;
2567
2568 TRACE("\n");
2569
2570 if(clear_ret)
2571 jsval_release(steal_ret(frame));
2572
2573 if((frame->flags & EXEC_CONSTRUCTOR) && !is_object_instance(frame->ret)) {
2574 jsval_release(frame->ret);
2575 IDispatch_AddRef(frame->this_obj);
2576 frame->ret = jsval_disp(frame->this_obj);
2577 }
2578
2579 jmp_abs(ctx, -1);
2580 return S_OK;
2581 }
2582
2583 static HRESULT interp_setret(script_ctx_t *ctx)
2584 {
2585 call_frame_t *frame = ctx->call_ctx;
2586
2587 TRACE("\n");
2588
2589 jsval_release(frame->ret);
2590 frame->ret = stack_pop(ctx);
2591 return S_OK;
2592 }
2593
2594 static HRESULT interp_push_ret(script_ctx_t *ctx)
2595 {
2596 call_frame_t *frame = ctx->call_ctx;
2597 HRESULT hres;
2598
2599 TRACE("\n");
2600
2601 hres = stack_push(ctx, frame->ret);
2602 if(SUCCEEDED(hres))
2603 frame->ret = jsval_undefined();
2604 return hres;
2605 }
2606
2607 typedef HRESULT (*op_func_t)(script_ctx_t*);
2608
2609 static const op_func_t op_funcs[] = {
2610 #define X(x,a,b,c) interp_##x,
2611 OP_LIST
2612 #undef X
2613 };
2614
2615 static const unsigned op_move[] = {
2616 #define X(a,x,b,c) x,
2617 OP_LIST
2618 #undef X
2619 };
2620
2621 static void pop_call_frame(script_ctx_t *ctx)
2622 {
2623 call_frame_t *frame = ctx->call_ctx;
2624
2625 frame->stack_base -= frame->pop_locals + frame->pop_variables;
2626
2627 assert(frame->scope == frame->base_scope);
2628
2629 /* If current scope will be kept alive, we need to transfer local variables to its variable object. */
2630 if(frame->scope && frame->scope->ref > 1) {
2631 HRESULT hres = detach_variable_object(ctx, frame, TRUE);
2632 if(FAILED(hres))
2633 ERR("Failed to detach variable object: %08x\n", hres);
2634 }
2635
2636 if(frame->arguments_obj)
2637 detach_arguments_object(frame->arguments_obj);
2638 if(frame->scope)
2639 scope_release(frame->scope);
2640
2641 if(frame->pop_variables)
2642 stack_popn(ctx, frame->pop_variables);
2643 stack_popn(ctx, frame->pop_locals);
2644
2645 ctx->call_ctx = frame->prev_frame;
2646
2647 if(frame->function_instance)
2648 jsdisp_release(frame->function_instance);
2649 if(frame->variable_obj)
2650 jsdisp_release(frame->variable_obj);
2651 if(frame->this_obj)
2652 IDispatch_Release(frame->this_obj);
2653 jsval_release(frame->ret);
2654 release_bytecode(frame->bytecode);
2655 heap_free(frame);
2656 }
2657
2658 static void print_backtrace(script_ctx_t *ctx)
2659 {
2660 unsigned depth = 0, i;
2661 call_frame_t *frame;
2662
2663 for(frame = ctx->call_ctx; frame; frame = frame->prev_frame) {
2664 TRACE_(jscript_except)("%u\t", depth);
2665 depth++;
2666
2667 if(frame->this_obj && frame->this_obj != to_disp(ctx->global) && frame->this_obj != ctx->host_global)
2668 TRACE_(jscript_except)("%p->", frame->this_obj);
2669 TRACE_(jscript_except)("%s(", frame->function->name ? debugstr_w(frame->function->name) : "[unnamed]");
2670 if(frame->base_scope && frame->base_scope->frame) {
2671 for(i=0; i < frame->argc; i++) {
2672 if(i < frame->function->param_cnt)
2673 TRACE_(jscript_except)("%s%s=%s", i ? ", " : "",
2674 debugstr_w(frame->function->params[i]),
2675 debugstr_jsval(ctx->stack[local_off(frame, -i-1)]));
2676 else
2677 TRACE_(jscript_except)("%s%s", i ? ", " : "",
2678 debugstr_jsval(ctx->stack[local_off(frame, -i-1)]));
2679 }
2680 }else {
2681 TRACE_(jscript_except)("[detached frame]");
2682 }
2683 TRACE_(jscript_except)(")\n");
2684
2685 if(!(frame->flags & EXEC_RETURN_TO_INTERP)) {
2686 TRACE_(jscript_except)("%u\t[native code]\n", depth);
2687 depth++;
2688 }
2689 }
2690 }
2691
2692 static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres)
2693 {
2694 except_frame_t *except_frame;
2695 call_frame_t *frame;
2696 jsval_t except_val;
2697 unsigned catch_off;
2698 HRESULT hres;
2699
2700 TRACE("%08x\n", exception_hres);
2701
2702 if(TRACE_ON(jscript_except)) {
2703 jsdisp_t *error_obj;
2704 jsval_t msg;
2705
2706 static const WCHAR messageW[] = {'m','e','s','s','a','g','e',0};
2707
2708 TRACE_(jscript_except)("Exception %08x %s", exception_hres, debugstr_jsval(ctx->ei.val));
2709 if(jsval_type(ctx->ei.val) == JSV_OBJECT) {
2710 error_obj = to_jsdisp(get_object(ctx->ei.val));
2711 if(error_obj) {
2712 hres = jsdisp_propget_name(error_obj, messageW, &msg);
2713 if(SUCCEEDED(hres)) {
2714 TRACE_(jscript_except)(" (message %s)", debugstr_jsval(msg));
2715 jsval_release(msg);
2716 }
2717 }
2718 }
2719 TRACE_(jscript_except)(" in:\n");
2720
2721 print_backtrace(ctx);
2722 }
2723
2724 for(frame = ctx->call_ctx; !frame->except_frame; frame = ctx->call_ctx) {
2725 DWORD flags;
2726
2727 while(frame->scope != frame->base_scope)
2728 scope_pop(&frame->scope);
2729
2730 stack_popn(ctx, ctx->stack_top-frame->stack_base);
2731
2732 flags = frame->flags;
2733 pop_call_frame(ctx);
2734 if(!(flags & EXEC_RETURN_TO_INTERP))
2735 return exception_hres;
2736 }
2737
2738 except_frame = frame->except_frame;
2739 catch_off = except_frame->catch_off;
2740
2741 assert(except_frame->stack_top <= ctx->stack_top);
2742 stack_popn(ctx, ctx->stack_top - except_frame->stack_top);
2743
2744 while(except_frame->scope != frame->scope)
2745 scope_pop(&frame->scope);
2746
2747 frame->ip = catch_off ? catch_off : except_frame->finally_off;
2748 if(catch_off) assert(frame->bytecode->instrs[frame->ip].op == OP_enter_catch);
2749
2750 except_val = ctx->ei.val;
2751 ctx->ei.val = jsval_undefined();
2752 clear_ei(ctx);
2753
2754 /* keep current except_frame if we're entering catch block with finally block associated */
2755 if(catch_off && except_frame->finally_off) {
2756 except_frame->catch_off = 0;
2757 }else {
2758 frame->except_frame = except_frame->next;
2759 heap_free(except_frame);
2760 }
2761
2762 hres = stack_push(ctx, except_val);
2763 if(FAILED(hres))
2764 return hres;
2765
2766 if(!catch_off)
2767 hres = stack_push(ctx, jsval_bool(FALSE));
2768 return hres;
2769 }
2770
2771 static HRESULT enter_bytecode(script_ctx_t *ctx, jsval_t *r)
2772 {
2773 call_frame_t *frame;
2774 jsop_t op;
2775 HRESULT hres = S_OK;
2776
2777 TRACE("\n");
2778
2779 while(1) {
2780 frame = ctx->call_ctx;
2781 op = frame->bytecode->instrs[frame->ip].op;
2782 hres = op_funcs[op](ctx);
2783 if(FAILED(hres)) {
2784 hres = unwind_exception(ctx, hres);
2785 if(FAILED(hres))
2786 return hres;
2787 }else if(frame->ip == -1) {
2788 const DWORD return_to_interp = frame->flags & EXEC_RETURN_TO_INTERP;
2789
2790 assert(ctx->stack_top == frame->stack_base);
2791 assert(frame->scope == frame->base_scope);
2792
2793 if(return_to_interp) {
2794 clear_ret(frame->prev_frame);
2795 frame->prev_frame->ret = steal_ret(frame);
2796 }else if(r) {
2797 *r = steal_ret(frame);
2798 }
2799 pop_call_frame(ctx);
2800 if(!return_to_interp)
2801 break;
2802 }else {
2803 frame->ip += op_move[op];
2804 }
2805 }
2806
2807 return S_OK;
2808 }
2809
2810 static HRESULT bind_event_target(script_ctx_t *ctx, function_code_t *func, jsdisp_t *func_obj)
2811 {
2812 IBindEventHandler *target;
2813 exprval_t exprval;
2814 IDispatch *disp;
2815 jsval_t v;
2816 HRESULT hres;
2817
2818 hres = identifier_eval(ctx, func->event_target, &exprval);
2819 if(FAILED(hres))
2820 return hres;
2821
2822 hres = exprval_to_value(ctx, &exprval, &v);
2823 if(FAILED(hres))
2824 return hres;
2825
2826 if(!is_object_instance(v)) {
2827 FIXME("Can't bind to %s\n", debugstr_jsval(v));
2828 jsval_release(v);
2829 }
2830
2831 disp = get_object(v);
2832 hres = IDispatch_QueryInterface(disp, &IID_IBindEventHandler, (void**)&target);
2833 if(SUCCEEDED(hres)) {
2834 hres = IBindEventHandler_BindHandler(target, func->name, (IDispatch*)&func_obj->IDispatchEx_iface);
2835 IBindEventHandler_Release(target);
2836 if(FAILED(hres))
2837 WARN("BindEvent failed: %08x\n", hres);
2838 }else {
2839 FIXME("No IBindEventHandler, not yet supported binding\n");
2840 }
2841
2842 IDispatch_Release(disp);
2843 return hres;
2844 }
2845
2846 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)
2847 {
2848 const unsigned orig_stack = ctx->stack_top;
2849 scope_chain_t *scope;
2850 unsigned i;
2851 jsval_t v;
2852 HRESULT hres;
2853
2854 /* If arguments are already on the stack, we may use them. */
2855 if(argv + argc == ctx->stack + ctx->stack_top) {
2856 frame->arguments_off = argv - ctx->stack;
2857 i = argc;
2858 }else {
2859 frame->arguments_off = ctx->stack_top;
2860 for(i = 0; i < argc; i++) {
2861 hres = jsval_copy(argv[i], &v);
2862 if(SUCCEEDED(hres))
2863 hres = stack_push(ctx, v);
2864 if(FAILED(hres)) {
2865 stack_popn(ctx, i);
2866 return hres;
2867 }
2868 }
2869 }
2870
2871 /* If fewer than declared arguments were passed, fill remaining with undefined value. */
2872 for(; i < frame->function->param_cnt; i++) {
2873 hres = stack_push(ctx, jsval_undefined());
2874 if(FAILED(hres)) {
2875 stack_popn(ctx, ctx->stack_top - orig_stack);
2876 return hres;
2877 }
2878 }
2879
2880 frame->pop_locals = ctx->stack_top - orig_stack;
2881
2882 frame->variables_off = ctx->stack_top;
2883
2884 for(i = 0; i < frame->function->var_cnt; i++) {
2885 hres = stack_push(ctx, jsval_undefined());
2886 if(FAILED(hres)) {
2887 stack_popn(ctx, ctx->stack_top - orig_stack);
2888 return hres;
2889 }
2890 }
2891
2892 frame->pop_variables = i;
2893
2894 hres = scope_push(scope_chain, variable_object, to_disp(variable_object), &scope);
2895 if(FAILED(hres)) {
2896 stack_popn(ctx, ctx->stack_top - orig_stack);
2897 return hres;
2898 }
2899
2900 for(i = 0; i < frame->function->func_cnt; i++) {
2901 if(frame->function->funcs[i].name && !frame->function->funcs[i].event_target) {
2902 jsdisp_t *func_obj;
2903 unsigned off;
2904
2905 hres = create_source_function(ctx, frame->bytecode, frame->function->funcs+i, scope, &func_obj);
2906 if(FAILED(hres)) {
2907 stack_popn(ctx, ctx->stack_top - orig_stack);
2908 scope_release(scope);
2909 return hres;
2910 }
2911
2912 off = local_off(frame, frame->function->funcs[i].local_ref);
2913 jsval_release(ctx->stack[off]);
2914 ctx->stack[off] = jsval_obj(func_obj);
2915 }
2916 }
2917
2918 scope->frame = frame;
2919 frame->base_scope = frame->scope = scope;
2920 return S_OK;
2921 }
2922
2923 HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, function_code_t *function, scope_chain_t *scope,
2924 IDispatch *this_obj, jsdisp_t *function_instance, jsdisp_t *variable_obj, unsigned argc, jsval_t *argv, jsval_t *r)
2925 {
2926 call_frame_t *frame;
2927 unsigned i;
2928 HRESULT hres;
2929
2930 for(i = 0; i < function->func_cnt; i++) {
2931 jsdisp_t *func_obj;
2932
2933 if(!function->funcs[i].event_target)
2934 continue;
2935
2936 hres = create_source_function(ctx, bytecode, function->funcs+i, scope, &func_obj);
2937 if(FAILED(hres))
2938 return hres;
2939
2940 hres = bind_event_target(ctx, function->funcs+i, func_obj);
2941 jsdisp_release(func_obj);
2942 if(FAILED(hres))
2943 return hres;
2944 }
2945
2946 if(flags & (EXEC_GLOBAL | EXEC_EVAL)) {
2947 for(i=0; i < function->var_cnt; i++) {
2948 TRACE("[%d] %s %d\n", i, debugstr_w(function->variables[i].name), function->variables[i].func_id);
2949 if(function->variables[i].func_id != -1) {
2950 jsdisp_t *func_obj;
2951
2952 hres = create_source_function(ctx, bytecode, function->funcs+function->variables[i].func_id, scope, &func_obj);
2953 if(FAILED(hres))
2954 return hres;
2955
2956 hres = jsdisp_propput_name(variable_obj, function->variables[i].name, jsval_obj(func_obj));
2957 jsdisp_release(func_obj);
2958 }else if(!(flags & EXEC_GLOBAL) || !lookup_global_members(ctx, function->variables[i].name, NULL)) {
2959 DISPID id = 0;
2960
2961 hres = jsdisp_get_id(variable_obj, function->variables[i].name, fdexNameEnsure, &id);
2962 if(FAILED(hres))
2963 return hres;
2964 }
2965 }
2966 }
2967
2968 /* ECMA-262 3rd Edition 11.2.3.7 */
2969 if(this_obj) {
2970 jsdisp_t *jsthis;
2971
2972 jsthis = iface_to_jsdisp(this_obj);
2973 if(jsthis) {
2974 if(jsthis->builtin_info->class == JSCLASS_GLOBAL || jsthis->builtin_info->class == JSCLASS_NONE)
2975 this_obj = NULL;
2976 jsdisp_release(jsthis);
2977 }
2978 }
2979
2980 if(ctx->call_ctx && (flags & EXEC_EVAL)) {
2981 hres = detach_variable_object(ctx, ctx->call_ctx, FALSE);
2982 if(FAILED(hres))
2983 return hres;
2984 }
2985
2986 frame = heap_alloc_zero(sizeof(*frame));
2987 if(!frame)
2988 return E_OUTOFMEMORY;
2989
2990 frame->function = function;
2991 frame->ret = jsval_undefined();
2992 frame->argc = argc;
2993 frame->bytecode = bytecode_addref(bytecode);
2994
2995 if(!(flags & (EXEC_GLOBAL|EXEC_EVAL))) {
2996 hres = setup_scope(ctx, frame, scope, variable_obj, argc, argv);
2997 if(FAILED(hres)) {
2998 release_bytecode(frame->bytecode);
2999 heap_free(frame);
3000 return hres;
3001 }
3002 }else if(scope) {
3003 frame->base_scope = frame->scope = scope_addref(scope);
3004 }
3005
3006 frame->ip = function->instr_off;
3007 frame->stack_base = ctx->stack_top;
3008 if(this_obj)
3009 frame->this_obj = this_obj;
3010 else if(ctx->host_global)
3011 frame->this_obj = ctx->host_global;
3012 else
3013 frame->this_obj = to_disp(ctx->global);
3014 IDispatch_AddRef(frame->this_obj);
3015
3016 if(function_instance)
3017 frame->function_instance = jsdisp_addref(function_instance);
3018
3019 frame->flags = flags;
3020 frame->variable_obj = jsdisp_addref(variable_obj);
3021
3022 frame->prev_frame = ctx->call_ctx;
3023 ctx->call_ctx = frame;
3024
3025 if(flags & EXEC_RETURN_TO_INTERP) {
3026 /*
3027 * We're called directly from interpreter, so we may just setup call frame and return.
3028 * Already running interpreter will take care of execution.
3029 */
3030 if(r)
3031 *r = jsval_undefined();
3032 return S_OK;
3033 }
3034
3035 return enter_bytecode(ctx, r);
3036 }