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