* Sync up to trunk head (r64377).
[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 v = stack_pop(ctx);
788 assert(is_bool(v));
789
790 if(!get_bool(v)) {
791 TRACE("passing exception\n");
792
793 ctx->script->ei.val = stack_pop(ctx);
794 return DISP_E_EXCEPTION;
795 }
796
797 stack_pop(ctx);
798 return S_OK;
799 }
800
801 /* ECMA-262 3rd Edition 13 */
802 static HRESULT interp_func(exec_ctx_t *ctx)
803 {
804 unsigned func_idx = get_op_uint(ctx, 0);
805 jsdisp_t *dispex;
806 HRESULT hres;
807
808 TRACE("%d\n", func_idx);
809
810 hres = create_source_function(ctx->script, ctx->code, ctx->func_code->funcs+func_idx,
811 ctx->scope_chain, &dispex);
812 if(FAILED(hres))
813 return hres;
814
815 return stack_push(ctx, jsval_obj(dispex));
816 }
817
818 /* ECMA-262 3rd Edition 11.2.1 */
819 static HRESULT interp_array(exec_ctx_t *ctx)
820 {
821 jsstr_t *name_str;
822 const WCHAR *name;
823 jsval_t v, namev;
824 IDispatch *obj;
825 DISPID id;
826 HRESULT hres;
827
828 TRACE("\n");
829
830 namev = stack_pop(ctx);
831
832 hres = stack_pop_object(ctx, &obj);
833 if(FAILED(hres)) {
834 jsval_release(namev);
835 return hres;
836 }
837
838 hres = to_flat_string(ctx->script, namev, &name_str, &name);
839 jsval_release(namev);
840 if(FAILED(hres)) {
841 IDispatch_Release(obj);
842 return hres;
843 }
844
845 hres = disp_get_id(ctx->script, obj, name, NULL, 0, &id);
846 jsstr_release(name_str);
847 if(SUCCEEDED(hres)) {
848 hres = disp_propget(ctx->script, obj, id, &v);
849 }else if(hres == DISP_E_UNKNOWNNAME) {
850 v = jsval_undefined();
851 hres = S_OK;
852 }
853 IDispatch_Release(obj);
854 if(FAILED(hres))
855 return hres;
856
857 return stack_push(ctx, v);
858 }
859
860 /* ECMA-262 3rd Edition 11.2.1 */
861 static HRESULT interp_member(exec_ctx_t *ctx)
862 {
863 const BSTR arg = get_op_bstr(ctx, 0);
864 IDispatch *obj;
865 jsval_t v;
866 DISPID id;
867 HRESULT hres;
868
869 TRACE("\n");
870
871 hres = stack_pop_object(ctx, &obj);
872 if(FAILED(hres))
873 return hres;
874
875 hres = disp_get_id(ctx->script, obj, arg, arg, 0, &id);
876 if(SUCCEEDED(hres)) {
877 hres = disp_propget(ctx->script, obj, id, &v);
878 }else if(hres == DISP_E_UNKNOWNNAME) {
879 v = jsval_undefined();
880 hres = S_OK;
881 }
882 IDispatch_Release(obj);
883 if(FAILED(hres))
884 return hres;
885
886 return stack_push(ctx, v);
887 }
888
889 /* ECMA-262 3rd Edition 11.2.1 */
890 static HRESULT interp_memberid(exec_ctx_t *ctx)
891 {
892 const unsigned arg = get_op_uint(ctx, 0);
893 jsval_t objv, namev;
894 const WCHAR *name;
895 jsstr_t *name_str;
896 IDispatch *obj;
897 DISPID id;
898 HRESULT hres;
899
900 TRACE("%x\n", arg);
901
902 namev = stack_pop(ctx);
903 objv = stack_pop(ctx);
904
905 hres = to_object(ctx->script, objv, &obj);
906 jsval_release(objv);
907 if(SUCCEEDED(hres)) {
908 hres = to_flat_string(ctx->script, namev, &name_str, &name);
909 if(FAILED(hres))
910 IDispatch_Release(obj);
911 }
912 jsval_release(namev);
913 if(FAILED(hres))
914 return hres;
915
916 hres = disp_get_id(ctx->script, obj, name, NULL, arg, &id);
917 jsstr_release(name_str);
918 if(FAILED(hres)) {
919 IDispatch_Release(obj);
920 if(hres == DISP_E_UNKNOWNNAME && !(arg & fdexNameEnsure)) {
921 obj = NULL;
922 id = JS_E_INVALID_PROPERTY;
923 }else {
924 ERR("failed %08x\n", hres);
925 return hres;
926 }
927 }
928
929 return stack_push_objid(ctx, obj, id);
930 }
931
932 /* ECMA-262 3rd Edition 11.2.1 */
933 static HRESULT interp_refval(exec_ctx_t *ctx)
934 {
935 IDispatch *disp;
936 jsval_t v;
937 DISPID id;
938 HRESULT hres;
939
940 TRACE("\n");
941
942 disp = stack_topn_objid(ctx, 0, &id);
943 if(!disp)
944 return throw_reference_error(ctx->script, JS_E_ILLEGAL_ASSIGN, NULL);
945
946 hres = disp_propget(ctx->script, disp, id, &v);
947 if(FAILED(hres))
948 return hres;
949
950 return stack_push(ctx, v);
951 }
952
953 /* ECMA-262 3rd Edition 11.2.2 */
954 static HRESULT interp_new(exec_ctx_t *ctx)
955 {
956 const unsigned argc = get_op_uint(ctx, 0);
957 jsval_t r, constr;
958 HRESULT hres;
959
960 TRACE("%d\n", argc);
961
962 constr = stack_topn(ctx, argc);
963
964 /* NOTE: Should use to_object here */
965
966 if(is_null(constr))
967 return throw_type_error(ctx->script, JS_E_OBJECT_EXPECTED, NULL);
968 else if(!is_object_instance(constr))
969 return throw_type_error(ctx->script, JS_E_INVALID_ACTION, NULL);
970 else if(!get_object(constr))
971 return throw_type_error(ctx->script, JS_E_INVALID_PROPERTY, NULL);
972
973 hres = disp_call_value(ctx->script, get_object(constr), NULL, DISPATCH_CONSTRUCT, argc, stack_args(ctx, argc), &r);
974 if(FAILED(hres))
975 return hres;
976
977 stack_popn(ctx, argc+1);
978 return stack_push(ctx, r);
979 }
980
981 /* ECMA-262 3rd Edition 11.2.3 */
982 static HRESULT interp_call(exec_ctx_t *ctx)
983 {
984 const unsigned argn = get_op_uint(ctx, 0);
985 const int do_ret = get_op_int(ctx, 1);
986 jsval_t r, obj;
987 HRESULT hres;
988
989 TRACE("%d %d\n", argn, do_ret);
990
991 obj = stack_topn(ctx, argn);
992 if(!is_object_instance(obj))
993 return throw_type_error(ctx->script, JS_E_INVALID_PROPERTY, NULL);
994
995 hres = disp_call_value(ctx->script, get_object(obj), NULL, DISPATCH_METHOD, argn, stack_args(ctx, argn),
996 do_ret ? &r : NULL);
997 if(FAILED(hres))
998 return hres;
999
1000 stack_popn(ctx, argn+1);
1001 return do_ret ? stack_push(ctx, r) : S_OK;
1002 }
1003
1004 /* ECMA-262 3rd Edition 11.2.3 */
1005 static HRESULT interp_call_member(exec_ctx_t *ctx)
1006 {
1007 const unsigned argn = get_op_uint(ctx, 0);
1008 const int do_ret = get_op_int(ctx, 1);
1009 IDispatch *obj;
1010 jsval_t r;
1011 DISPID id;
1012 HRESULT hres;
1013
1014 TRACE("%d %d\n", argn, do_ret);
1015
1016 obj = stack_topn_objid(ctx, argn, &id);
1017 if(!obj)
1018 return throw_type_error(ctx->script, id, NULL);
1019
1020 hres = disp_call(ctx->script, obj, id, DISPATCH_METHOD, argn, stack_args(ctx, argn), do_ret ? &r : NULL);
1021 if(FAILED(hres))
1022 return hres;
1023
1024 stack_popn(ctx, argn+2);
1025 return do_ret ? stack_push(ctx, r) : S_OK;
1026
1027 }
1028
1029 /* ECMA-262 3rd Edition 11.1.1 */
1030 static HRESULT interp_this(exec_ctx_t *ctx)
1031 {
1032 TRACE("\n");
1033
1034 IDispatch_AddRef(ctx->this_obj);
1035 return stack_push(ctx, jsval_disp(ctx->this_obj));
1036 }
1037
1038 /* ECMA-262 3rd Edition 10.1.4 */
1039 static HRESULT interp_ident(exec_ctx_t *ctx)
1040 {
1041 const BSTR arg = get_op_bstr(ctx, 0);
1042 exprval_t exprval;
1043 jsval_t v;
1044 HRESULT hres;
1045
1046 TRACE("%s\n", debugstr_w(arg));
1047
1048 hres = identifier_eval(ctx->script, arg, &exprval);
1049 if(FAILED(hres))
1050 return hres;
1051
1052 if(exprval.type == EXPRVAL_INVALID)
1053 return throw_type_error(ctx->script, JS_E_UNDEFINED_VARIABLE, arg);
1054
1055 hres = exprval_to_value(ctx->script, &exprval, &v);
1056 exprval_release(&exprval);
1057 if(FAILED(hres))
1058 return hres;
1059
1060 return stack_push(ctx, v);
1061 }
1062
1063 /* ECMA-262 3rd Edition 10.1.4 */
1064 static HRESULT interp_identid(exec_ctx_t *ctx)
1065 {
1066 const BSTR arg = get_op_bstr(ctx, 0);
1067 const unsigned flags = get_op_uint(ctx, 1);
1068 exprval_t exprval;
1069 HRESULT hres;
1070
1071 TRACE("%s %x\n", debugstr_w(arg), flags);
1072
1073 hres = identifier_eval(ctx->script, arg, &exprval);
1074 if(FAILED(hres))
1075 return hres;
1076
1077 if(exprval.type == EXPRVAL_INVALID && (flags & fdexNameEnsure)) {
1078 DISPID id;
1079
1080 hres = jsdisp_get_id(ctx->script->global, arg, fdexNameEnsure, &id);
1081 if(FAILED(hres))
1082 return hres;
1083
1084 exprval_set_idref(&exprval, to_disp(ctx->script->global), id);
1085 }
1086
1087 if(exprval.type != EXPRVAL_IDREF) {
1088 WARN("invalid ref\n");
1089 exprval_release(&exprval);
1090 return stack_push_objid(ctx, NULL, JS_E_OBJECT_EXPECTED);
1091 }
1092
1093 return stack_push_objid(ctx, exprval.u.idref.disp, exprval.u.idref.id);
1094 }
1095
1096 /* ECMA-262 3rd Edition 7.8.1 */
1097 static HRESULT interp_null(exec_ctx_t *ctx)
1098 {
1099 TRACE("\n");
1100
1101 return stack_push(ctx, jsval_null());
1102 }
1103
1104 /* ECMA-262 3rd Edition 7.8.2 */
1105 static HRESULT interp_bool(exec_ctx_t *ctx)
1106 {
1107 const int arg = get_op_int(ctx, 0);
1108
1109 TRACE("%s\n", arg ? "true" : "false");
1110
1111 return stack_push(ctx, jsval_bool(arg));
1112 }
1113
1114 /* ECMA-262 3rd Edition 7.8.3 */
1115 static HRESULT interp_int(exec_ctx_t *ctx)
1116 {
1117 const int arg = get_op_int(ctx, 0);
1118
1119 TRACE("%d\n", arg);
1120
1121 return stack_push(ctx, jsval_number(arg));
1122 }
1123
1124 /* ECMA-262 3rd Edition 7.8.3 */
1125 static HRESULT interp_double(exec_ctx_t *ctx)
1126 {
1127 const double arg = get_op_double(ctx);
1128
1129 TRACE("%lf\n", arg);
1130
1131 return stack_push(ctx, jsval_number(arg));
1132 }
1133
1134 /* ECMA-262 3rd Edition 7.8.4 */
1135 static HRESULT interp_str(exec_ctx_t *ctx)
1136 {
1137 jsstr_t *str = get_op_str(ctx, 0);
1138
1139 TRACE("%s\n", debugstr_jsstr(str));
1140
1141 return stack_push(ctx, jsval_string(jsstr_addref(str)));
1142 }
1143
1144 /* ECMA-262 3rd Edition 7.8 */
1145 static HRESULT interp_regexp(exec_ctx_t *ctx)
1146 {
1147 jsstr_t *source = get_op_str(ctx, 0);
1148 const unsigned flags = get_op_uint(ctx, 1);
1149 jsdisp_t *regexp;
1150 HRESULT hres;
1151
1152 TRACE("%s %x\n", debugstr_jsstr(source), flags);
1153
1154 hres = create_regexp(ctx->script, source, flags, &regexp);
1155 if(FAILED(hres))
1156 return hres;
1157
1158 return stack_push(ctx, jsval_obj(regexp));
1159 }
1160
1161 /* ECMA-262 3rd Edition 11.1.4 */
1162 static HRESULT interp_carray(exec_ctx_t *ctx)
1163 {
1164 const unsigned arg = get_op_uint(ctx, 0);
1165 jsdisp_t *array;
1166 jsval_t val;
1167 unsigned i;
1168 HRESULT hres;
1169
1170 TRACE("%u\n", arg);
1171
1172 hres = create_array(ctx->script, arg, &array);
1173 if(FAILED(hres))
1174 return hres;
1175
1176 i = arg;
1177 while(i--) {
1178 val = stack_pop(ctx);
1179 hres = jsdisp_propput_idx(array, i, val);
1180 jsval_release(val);
1181 if(FAILED(hres)) {
1182 jsdisp_release(array);
1183 return hres;
1184 }
1185 }
1186
1187 return stack_push(ctx, jsval_obj(array));
1188 }
1189
1190 /* ECMA-262 3rd Edition 11.1.5 */
1191 static HRESULT interp_new_obj(exec_ctx_t *ctx)
1192 {
1193 jsdisp_t *obj;
1194 HRESULT hres;
1195
1196 TRACE("\n");
1197
1198 hres = create_object(ctx->script, NULL, &obj);
1199 if(FAILED(hres))
1200 return hres;
1201
1202 return stack_push(ctx, jsval_obj(obj));
1203 }
1204
1205 /* ECMA-262 3rd Edition 11.1.5 */
1206 static HRESULT interp_obj_prop(exec_ctx_t *ctx)
1207 {
1208 const BSTR name = get_op_bstr(ctx, 0);
1209 jsdisp_t *obj;
1210 jsval_t val;
1211 HRESULT hres;
1212
1213 TRACE("%s\n", debugstr_w(name));
1214
1215 val = stack_pop(ctx);
1216
1217 assert(is_object_instance(stack_top(ctx)));
1218 obj = as_jsdisp(get_object(stack_top(ctx)));
1219
1220 hres = jsdisp_propput_name(obj, name, val);
1221 jsval_release(val);
1222 return hres;
1223 }
1224
1225 /* ECMA-262 3rd Edition 11.11 */
1226 static HRESULT interp_cnd_nz(exec_ctx_t *ctx)
1227 {
1228 const unsigned arg = get_op_uint(ctx, 0);
1229 BOOL b;
1230 HRESULT hres;
1231
1232 TRACE("\n");
1233
1234 hres = to_boolean(stack_top(ctx), &b);
1235 if(FAILED(hres))
1236 return hres;
1237
1238 if(b) {
1239 ctx->ip = arg;
1240 }else {
1241 stack_popn(ctx, 1);
1242 ctx->ip++;
1243 }
1244 return S_OK;
1245 }
1246
1247 /* ECMA-262 3rd Edition 11.11 */
1248 static HRESULT interp_cnd_z(exec_ctx_t *ctx)
1249 {
1250 const unsigned arg = get_op_uint(ctx, 0);
1251 BOOL b;
1252 HRESULT hres;
1253
1254 TRACE("\n");
1255
1256 hres = to_boolean(stack_top(ctx), &b);
1257 if(FAILED(hres))
1258 return hres;
1259
1260 if(b) {
1261 stack_popn(ctx, 1);
1262 ctx->ip++;
1263 }else {
1264 ctx->ip = arg;
1265 }
1266 return S_OK;
1267 }
1268
1269 /* ECMA-262 3rd Edition 11.10 */
1270 static HRESULT interp_or(exec_ctx_t *ctx)
1271 {
1272 INT l, r;
1273 HRESULT hres;
1274
1275 TRACE("\n");
1276
1277 hres = stack_pop_int(ctx, &r);
1278 if(FAILED(hres))
1279 return hres;
1280
1281 hres = stack_pop_int(ctx, &l);
1282 if(FAILED(hres))
1283 return hres;
1284
1285 return stack_push(ctx, jsval_number(l|r));
1286 }
1287
1288 /* ECMA-262 3rd Edition 11.10 */
1289 static HRESULT interp_xor(exec_ctx_t *ctx)
1290 {
1291 INT l, r;
1292 HRESULT hres;
1293
1294 TRACE("\n");
1295
1296 hres = stack_pop_int(ctx, &r);
1297 if(FAILED(hres))
1298 return hres;
1299
1300 hres = stack_pop_int(ctx, &l);
1301 if(FAILED(hres))
1302 return hres;
1303
1304 return stack_push(ctx, jsval_number(l^r));
1305 }
1306
1307 /* ECMA-262 3rd Edition 11.10 */
1308 static HRESULT interp_and(exec_ctx_t *ctx)
1309 {
1310 INT l, r;
1311 HRESULT hres;
1312
1313 TRACE("\n");
1314
1315 hres = stack_pop_int(ctx, &r);
1316 if(FAILED(hres))
1317 return hres;
1318
1319 hres = stack_pop_int(ctx, &l);
1320 if(FAILED(hres))
1321 return hres;
1322
1323 return stack_push(ctx, jsval_number(l&r));
1324 }
1325
1326 /* ECMA-262 3rd Edition 11.8.6 */
1327 static HRESULT interp_instanceof(exec_ctx_t *ctx)
1328 {
1329 jsdisp_t *obj, *iter, *tmp = NULL;
1330 jsval_t prot, v;
1331 BOOL ret = FALSE;
1332 HRESULT hres;
1333
1334 static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0};
1335
1336 v = stack_pop(ctx);
1337 if(!is_object_instance(v) || !get_object(v)) {
1338 jsval_release(v);
1339 return throw_type_error(ctx->script, JS_E_FUNCTION_EXPECTED, NULL);
1340 }
1341
1342 obj = iface_to_jsdisp((IUnknown*)get_object(v));
1343 IDispatch_Release(get_object(v));
1344 if(!obj) {
1345 FIXME("non-jsdisp objects not supported\n");
1346 return E_FAIL;
1347 }
1348
1349 if(is_class(obj, JSCLASS_FUNCTION)) {
1350 hres = jsdisp_propget_name(obj, prototypeW, &prot);
1351 }else {
1352 hres = throw_type_error(ctx->script, JS_E_FUNCTION_EXPECTED, NULL);
1353 }
1354 jsdisp_release(obj);
1355 if(FAILED(hres))
1356 return hres;
1357
1358 v = stack_pop(ctx);
1359
1360 if(is_object_instance(prot)) {
1361 if(is_object_instance(v))
1362 tmp = iface_to_jsdisp((IUnknown*)get_object(v));
1363 for(iter = tmp; !ret && iter; iter = iter->prototype) {
1364 hres = disp_cmp(get_object(prot), to_disp(iter), &ret);
1365 if(FAILED(hres))
1366 break;
1367 }
1368
1369 if(tmp)
1370 jsdisp_release(tmp);
1371 }else {
1372 FIXME("prototype is not an object\n");
1373 hres = E_FAIL;
1374 }
1375
1376 jsval_release(prot);
1377 jsval_release(v);
1378 if(FAILED(hres))
1379 return hres;
1380
1381 return stack_push(ctx, jsval_bool(ret));
1382 }
1383
1384 /* ECMA-262 3rd Edition 11.8.7 */
1385 static HRESULT interp_in(exec_ctx_t *ctx)
1386 {
1387 const WCHAR *str;
1388 jsstr_t *jsstr;
1389 jsval_t obj, v;
1390 DISPID id = 0;
1391 BOOL ret;
1392 HRESULT hres;
1393
1394 TRACE("\n");
1395
1396 obj = stack_pop(ctx);
1397 if(!is_object_instance(obj) || !get_object(obj)) {
1398 jsval_release(obj);
1399 return throw_type_error(ctx->script, JS_E_OBJECT_EXPECTED, NULL);
1400 }
1401
1402 v = stack_pop(ctx);
1403 hres = to_flat_string(ctx->script, v, &jsstr, &str);
1404 jsval_release(v);
1405 if(FAILED(hres)) {
1406 IDispatch_Release(get_object(obj));
1407 return hres;
1408 }
1409
1410 hres = disp_get_id(ctx->script, get_object(obj), str, NULL, 0, &id);
1411 IDispatch_Release(get_object(obj));
1412 jsstr_release(jsstr);
1413 if(SUCCEEDED(hres))
1414 ret = TRUE;
1415 else if(hres == DISP_E_UNKNOWNNAME)
1416 ret = FALSE;
1417 else
1418 return hres;
1419
1420 return stack_push(ctx, jsval_bool(ret));
1421 }
1422
1423 /* ECMA-262 3rd Edition 11.6.1 */
1424 static HRESULT add_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, jsval_t *ret)
1425 {
1426 jsval_t r, l;
1427 HRESULT hres;
1428
1429 hres = to_primitive(ctx, lval, &l, NO_HINT);
1430 if(FAILED(hres))
1431 return hres;
1432
1433 hres = to_primitive(ctx, rval, &r, NO_HINT);
1434 if(FAILED(hres)) {
1435 jsval_release(l);
1436 return hres;
1437 }
1438
1439 if(is_string(l) || is_string(r)) {
1440 jsstr_t *lstr, *rstr = NULL;
1441
1442 hres = to_string(ctx, l, &lstr);
1443 if(SUCCEEDED(hres))
1444 hres = to_string(ctx, r, &rstr);
1445
1446 if(SUCCEEDED(hres)) {
1447 jsstr_t *ret_str;
1448
1449 ret_str = jsstr_concat(lstr, rstr);
1450 if(ret_str)
1451 *ret = jsval_string(ret_str);
1452 else
1453 hres = E_OUTOFMEMORY;
1454 }
1455
1456 jsstr_release(lstr);
1457 if(rstr)
1458 jsstr_release(rstr);
1459 }else {
1460 double nl, nr;
1461
1462 hres = to_number(ctx, l, &nl);
1463 if(SUCCEEDED(hres)) {
1464 hres = to_number(ctx, r, &nr);
1465 if(SUCCEEDED(hres))
1466 *ret = jsval_number(nl+nr);
1467 }
1468 }
1469
1470 jsval_release(r);
1471 jsval_release(l);
1472 return hres;
1473 }
1474
1475 /* ECMA-262 3rd Edition 11.6.1 */
1476 static HRESULT interp_add(exec_ctx_t *ctx)
1477 {
1478 jsval_t l, r, ret;
1479 HRESULT hres;
1480
1481 r = stack_pop(ctx);
1482 l = stack_pop(ctx);
1483
1484 TRACE("%s + %s\n", debugstr_jsval(l), debugstr_jsval(r));
1485
1486 hres = add_eval(ctx->script, l, r, &ret);
1487 jsval_release(l);
1488 jsval_release(r);
1489 if(FAILED(hres))
1490 return hres;
1491
1492 return stack_push(ctx, ret);
1493 }
1494
1495 /* ECMA-262 3rd Edition 11.6.2 */
1496 static HRESULT interp_sub(exec_ctx_t *ctx)
1497 {
1498 double l, r;
1499 HRESULT hres;
1500
1501 TRACE("\n");
1502
1503 hres = stack_pop_number(ctx, &r);
1504 if(FAILED(hres))
1505 return hres;
1506
1507 hres = stack_pop_number(ctx, &l);
1508 if(FAILED(hres))
1509 return hres;
1510
1511 return stack_push(ctx, jsval_number(l-r));
1512 }
1513
1514 /* ECMA-262 3rd Edition 11.5.1 */
1515 static HRESULT interp_mul(exec_ctx_t *ctx)
1516 {
1517 double l, r;
1518 HRESULT hres;
1519
1520 TRACE("\n");
1521
1522 hres = stack_pop_number(ctx, &r);
1523 if(FAILED(hres))
1524 return hres;
1525
1526 hres = stack_pop_number(ctx, &l);
1527 if(FAILED(hres))
1528 return hres;
1529
1530 return stack_push(ctx, jsval_number(l*r));
1531 }
1532
1533 /* ECMA-262 3rd Edition 11.5.2 */
1534 static HRESULT interp_div(exec_ctx_t *ctx)
1535 {
1536 double l, r;
1537 HRESULT hres;
1538
1539 TRACE("\n");
1540
1541 hres = stack_pop_number(ctx, &r);
1542 if(FAILED(hres))
1543 return hres;
1544
1545 hres = stack_pop_number(ctx, &l);
1546 if(FAILED(hres))
1547 return hres;
1548
1549 return stack_push(ctx, jsval_number(l/r));
1550 }
1551
1552 /* ECMA-262 3rd Edition 11.5.3 */
1553 static HRESULT interp_mod(exec_ctx_t *ctx)
1554 {
1555 double l, r;
1556 HRESULT hres;
1557
1558 TRACE("\n");
1559
1560 hres = stack_pop_number(ctx, &r);
1561 if(FAILED(hres))
1562 return hres;
1563
1564 hres = stack_pop_number(ctx, &l);
1565 if(FAILED(hres))
1566 return hres;
1567
1568 return stack_push(ctx, jsval_number(fmod(l, r)));
1569 }
1570
1571 /* ECMA-262 3rd Edition 11.4.2 */
1572 static HRESULT interp_delete(exec_ctx_t *ctx)
1573 {
1574 jsval_t objv, namev;
1575 IDispatch *obj;
1576 jsstr_t *name;
1577 BOOL ret;
1578 HRESULT hres;
1579
1580 TRACE("\n");
1581
1582 namev = stack_pop(ctx);
1583 objv = stack_pop(ctx);
1584
1585 hres = to_object(ctx->script, objv, &obj);
1586 jsval_release(objv);
1587 if(FAILED(hres)) {
1588 jsval_release(namev);
1589 return hres;
1590 }
1591
1592 hres = to_string(ctx->script, namev, &name);
1593 jsval_release(namev);
1594 if(FAILED(hres)) {
1595 IDispatch_Release(obj);
1596 return hres;
1597 }
1598
1599 hres = disp_delete_name(ctx->script, obj, name, &ret);
1600 IDispatch_Release(obj);
1601 jsstr_release(name);
1602 if(FAILED(hres))
1603 return hres;
1604
1605 return stack_push(ctx, jsval_bool(ret));
1606 }
1607
1608 /* ECMA-262 3rd Edition 11.4.2 */
1609 static HRESULT interp_delete_ident(exec_ctx_t *ctx)
1610 {
1611 const BSTR arg = get_op_bstr(ctx, 0);
1612 exprval_t exprval;
1613 BOOL ret;
1614 HRESULT hres;
1615
1616 TRACE("%s\n", debugstr_w(arg));
1617
1618 hres = identifier_eval(ctx->script, arg, &exprval);
1619 if(FAILED(hres))
1620 return hres;
1621
1622 switch(exprval.type) {
1623 case EXPRVAL_IDREF:
1624 hres = disp_delete(exprval.u.idref.disp, exprval.u.idref.id, &ret);
1625 IDispatch_Release(exprval.u.idref.disp);
1626 if(FAILED(hres))
1627 return ret;
1628 break;
1629 case EXPRVAL_INVALID:
1630 ret = TRUE;
1631 break;
1632 default:
1633 FIXME("Unsupported exprval\n");
1634 exprval_release(&exprval);
1635 return E_NOTIMPL;
1636 }
1637
1638
1639 return stack_push(ctx, jsval_bool(ret));
1640 }
1641
1642 /* ECMA-262 3rd Edition 11.4.2 */
1643 static HRESULT interp_void(exec_ctx_t *ctx)
1644 {
1645 TRACE("\n");
1646
1647 stack_popn(ctx, 1);
1648 return stack_push(ctx, jsval_undefined());
1649 }
1650
1651 /* ECMA-262 3rd Edition 11.4.3 */
1652 static HRESULT typeof_string(jsval_t v, const WCHAR **ret)
1653 {
1654 switch(jsval_type(v)) {
1655 case JSV_UNDEFINED:
1656 *ret = undefinedW;
1657 break;
1658 case JSV_NULL:
1659 *ret = objectW;
1660 break;
1661 case JSV_OBJECT: {
1662 jsdisp_t *dispex;
1663
1664 if(get_object(v) && (dispex = iface_to_jsdisp((IUnknown*)get_object(v)))) {
1665 *ret = is_class(dispex, JSCLASS_FUNCTION) ? functionW : objectW;
1666 jsdisp_release(dispex);
1667 }else {
1668 *ret = objectW;
1669 }
1670 break;
1671 }
1672 case JSV_STRING:
1673 *ret = stringW;
1674 break;
1675 case JSV_NUMBER:
1676 *ret = numberW;
1677 break;
1678 case JSV_BOOL:
1679 *ret = booleanW;
1680 break;
1681 case JSV_VARIANT:
1682 FIXME("unhandled variant %s\n", debugstr_variant(get_variant(v)));
1683 return E_NOTIMPL;
1684 }
1685
1686 return S_OK;
1687 }
1688
1689 /* ECMA-262 3rd Edition 11.4.3 */
1690 static HRESULT interp_typeofid(exec_ctx_t *ctx)
1691 {
1692 const WCHAR *ret;
1693 IDispatch *obj;
1694 jsval_t v;
1695 DISPID id;
1696 HRESULT hres;
1697
1698 TRACE("\n");
1699
1700 obj = stack_pop_objid(ctx, &id);
1701 if(!obj)
1702 return stack_push(ctx, jsval_string(jsstr_undefined()));
1703
1704 hres = disp_propget(ctx->script, obj, id, &v);
1705 IDispatch_Release(obj);
1706 if(FAILED(hres))
1707 return stack_push_string(ctx, unknownW);
1708
1709 hres = typeof_string(v, &ret);
1710 jsval_release(v);
1711 if(FAILED(hres))
1712 return hres;
1713
1714 return stack_push_string(ctx, ret);
1715 }
1716
1717 /* ECMA-262 3rd Edition 11.4.3 */
1718 static HRESULT interp_typeofident(exec_ctx_t *ctx)
1719 {
1720 const BSTR arg = get_op_bstr(ctx, 0);
1721 exprval_t exprval;
1722 const WCHAR *ret;
1723 jsval_t v;
1724 HRESULT hres;
1725
1726 TRACE("%s\n", debugstr_w(arg));
1727
1728 hres = identifier_eval(ctx->script, arg, &exprval);
1729 if(FAILED(hres))
1730 return hres;
1731
1732 if(exprval.type == EXPRVAL_INVALID) {
1733 hres = stack_push(ctx, jsval_string(jsstr_undefined()));
1734 exprval_release(&exprval);
1735 return hres;
1736 }
1737
1738 hres = exprval_to_value(ctx->script, &exprval, &v);
1739 exprval_release(&exprval);
1740 if(FAILED(hres))
1741 return hres;
1742
1743 hres = typeof_string(v, &ret);
1744 jsval_release(v);
1745 if(FAILED(hres))
1746 return hres;
1747
1748 return stack_push_string(ctx, ret);
1749 }
1750
1751 /* ECMA-262 3rd Edition 11.4.3 */
1752 static HRESULT interp_typeof(exec_ctx_t *ctx)
1753 {
1754 const WCHAR *ret;
1755 jsval_t v;
1756 HRESULT hres;
1757
1758 TRACE("\n");
1759
1760 v = stack_pop(ctx);
1761 hres = typeof_string(v, &ret);
1762 jsval_release(v);
1763 if(FAILED(hres))
1764 return hres;
1765
1766 return stack_push_string(ctx, ret);
1767 }
1768
1769 /* ECMA-262 3rd Edition 11.4.7 */
1770 static HRESULT interp_minus(exec_ctx_t *ctx)
1771 {
1772 double n;
1773 HRESULT hres;
1774
1775 TRACE("\n");
1776
1777 hres = stack_pop_number(ctx, &n);
1778 if(FAILED(hres))
1779 return hres;
1780
1781 return stack_push(ctx, jsval_number(-n));
1782 }
1783
1784 /* ECMA-262 3rd Edition 11.4.6 */
1785 static HRESULT interp_tonum(exec_ctx_t *ctx)
1786 {
1787 jsval_t v;
1788 double n;
1789 HRESULT hres;
1790
1791 TRACE("\n");
1792
1793 v = stack_pop(ctx);
1794 hres = to_number(ctx->script, v, &n);
1795 jsval_release(v);
1796 if(FAILED(hres))
1797 return hres;
1798
1799 return stack_push(ctx, jsval_number(n));
1800 }
1801
1802 /* ECMA-262 3rd Edition 11.3.1 */
1803 static HRESULT interp_postinc(exec_ctx_t *ctx)
1804 {
1805 const int arg = get_op_int(ctx, 0);
1806 IDispatch *obj;
1807 DISPID id;
1808 jsval_t v;
1809 HRESULT hres;
1810
1811 TRACE("%d\n", arg);
1812
1813 obj = stack_pop_objid(ctx, &id);
1814 if(!obj)
1815 return throw_type_error(ctx->script, JS_E_OBJECT_EXPECTED, NULL);
1816
1817 hres = disp_propget(ctx->script, obj, id, &v);
1818 if(SUCCEEDED(hres)) {
1819 double n;
1820
1821 hres = to_number(ctx->script, v, &n);
1822 if(SUCCEEDED(hres))
1823 hres = disp_propput(ctx->script, obj, id, jsval_number(n+(double)arg));
1824 if(FAILED(hres))
1825 jsval_release(v);
1826 }
1827 IDispatch_Release(obj);
1828 if(FAILED(hres))
1829 return hres;
1830
1831 return stack_push(ctx, v);
1832 }
1833
1834 /* ECMA-262 3rd Edition 11.4.4, 11.4.5 */
1835 static HRESULT interp_preinc(exec_ctx_t *ctx)
1836 {
1837 const int arg = get_op_int(ctx, 0);
1838 IDispatch *obj;
1839 double ret;
1840 DISPID id;
1841 jsval_t v;
1842 HRESULT hres;
1843
1844 TRACE("%d\n", arg);
1845
1846 obj = stack_pop_objid(ctx, &id);
1847 if(!obj)
1848 return throw_type_error(ctx->script, JS_E_OBJECT_EXPECTED, NULL);
1849
1850 hres = disp_propget(ctx->script, obj, id, &v);
1851 if(SUCCEEDED(hres)) {
1852 double n;
1853
1854 hres = to_number(ctx->script, v, &n);
1855 jsval_release(v);
1856 if(SUCCEEDED(hres)) {
1857 ret = n+(double)arg;
1858 hres = disp_propput(ctx->script, obj, id, jsval_number(ret));
1859 }
1860 }
1861 IDispatch_Release(obj);
1862 if(FAILED(hres))
1863 return hres;
1864
1865 return stack_push(ctx, jsval_number(ret));
1866 }
1867
1868 /* ECMA-262 3rd Edition 11.9.3 */
1869 static HRESULT equal_values(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL *ret)
1870 {
1871 if(jsval_type(lval) == jsval_type(rval) || (is_number(lval) && is_number(rval)))
1872 return equal2_values(lval, rval, ret);
1873
1874 /* FIXME: NULL disps should be handled in more general way */
1875 if(is_object_instance(lval) && !get_object(lval))
1876 return equal_values(ctx, jsval_null(), rval, ret);
1877 if(is_object_instance(rval) && !get_object(rval))
1878 return equal_values(ctx, lval, jsval_null(), ret);
1879
1880 if((is_null(lval) && is_undefined(rval)) || (is_undefined(lval) && is_null(rval))) {
1881 *ret = TRUE;
1882 return S_OK;
1883 }
1884
1885 if(is_string(lval) && is_number(rval)) {
1886 double n;
1887 HRESULT hres;
1888
1889 hres = to_number(ctx, lval, &n);
1890 if(FAILED(hres))
1891 return hres;
1892
1893 /* FIXME: optimize */
1894 return equal_values(ctx, jsval_number(n), rval, ret);
1895 }
1896
1897 if(is_string(rval) && is_number(lval)) {
1898 double n;
1899 HRESULT hres;
1900
1901 hres = to_number(ctx, rval, &n);
1902 if(FAILED(hres))
1903 return hres;
1904
1905 /* FIXME: optimize */
1906 return equal_values(ctx, lval, jsval_number(n), ret);
1907 }
1908
1909 if(is_bool(rval))
1910 return equal_values(ctx, lval, jsval_number(get_bool(rval) ? 1 : 0), ret);
1911
1912 if(is_bool(lval))
1913 return equal_values(ctx, jsval_number(get_bool(lval) ? 1 : 0), rval, ret);
1914
1915
1916 if(is_object_instance(rval) && (is_string(lval) || is_number(lval))) {
1917 jsval_t prim;
1918 HRESULT hres;
1919
1920 hres = to_primitive(ctx, rval, &prim, NO_HINT);
1921 if(FAILED(hres))
1922 return hres;
1923
1924 hres = equal_values(ctx, lval, prim, ret);
1925 jsval_release(prim);
1926 return hres;
1927 }
1928
1929
1930 if(is_object_instance(lval) && (is_string(rval) || is_number(rval))) {
1931 jsval_t prim;
1932 HRESULT hres;
1933
1934 hres = to_primitive(ctx, lval, &prim, NO_HINT);
1935 if(FAILED(hres))
1936 return hres;
1937
1938 hres = equal_values(ctx, prim, rval, ret);
1939 jsval_release(prim);
1940 return hres;
1941 }
1942
1943
1944 *ret = FALSE;
1945 return S_OK;
1946 }
1947
1948 /* ECMA-262 3rd Edition 11.9.1 */
1949 static HRESULT interp_eq(exec_ctx_t *ctx)
1950 {
1951 jsval_t l, r;
1952 BOOL b;
1953 HRESULT hres;
1954
1955 r = stack_pop(ctx);
1956 l = stack_pop(ctx);
1957
1958 TRACE("%s == %s\n", debugstr_jsval(l), debugstr_jsval(r));
1959
1960 hres = equal_values(ctx->script, l, r, &b);
1961 jsval_release(l);
1962 jsval_release(r);
1963 if(FAILED(hres))
1964 return hres;
1965
1966 return stack_push(ctx, jsval_bool(b));
1967 }
1968
1969 /* ECMA-262 3rd Edition 11.9.2 */
1970 static HRESULT interp_neq(exec_ctx_t *ctx)
1971 {
1972 jsval_t l, r;
1973 BOOL b;
1974 HRESULT hres;
1975
1976 r = stack_pop(ctx);
1977 l = stack_pop(ctx);
1978
1979 TRACE("%s != %s\n", debugstr_jsval(l), debugstr_jsval(r));
1980
1981 hres = equal_values(ctx->script, l, r, &b);
1982 jsval_release(l);
1983 jsval_release(r);
1984 if(FAILED(hres))
1985 return hres;
1986
1987 return stack_push(ctx, jsval_bool(!b));
1988 }
1989
1990 /* ECMA-262 3rd Edition 11.9.4 */
1991 static HRESULT interp_eq2(exec_ctx_t *ctx)
1992 {
1993 jsval_t l, r;
1994 BOOL b;
1995 HRESULT hres;
1996
1997 r = stack_pop(ctx);
1998 l = stack_pop(ctx);
1999
2000 TRACE("%s === %s\n", debugstr_jsval(l), debugstr_jsval(r));
2001
2002 hres = equal2_values(r, l, &b);
2003 jsval_release(l);
2004 jsval_release(r);
2005 if(FAILED(hres))
2006 return hres;
2007
2008 return stack_push(ctx, jsval_bool(b));
2009 }
2010
2011 /* ECMA-262 3rd Edition 11.9.5 */
2012 static HRESULT interp_neq2(exec_ctx_t *ctx)
2013 {
2014 jsval_t l, r;
2015 BOOL b;
2016 HRESULT hres;
2017
2018 TRACE("\n");
2019
2020 r = stack_pop(ctx);
2021 l = stack_pop(ctx);
2022
2023 hres = equal2_values(r, l, &b);
2024 jsval_release(l);
2025 jsval_release(r);
2026 if(FAILED(hres))
2027 return hres;
2028
2029 return stack_push(ctx, jsval_bool(!b));
2030 }
2031
2032 /* ECMA-262 3rd Edition 11.8.5 */
2033 static HRESULT less_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL greater, BOOL *ret)
2034 {
2035 double ln, rn;
2036 jsval_t l, r;
2037 HRESULT hres;
2038
2039 hres = to_primitive(ctx, lval, &l, NO_HINT);
2040 if(FAILED(hres))
2041 return hres;
2042
2043 hres = to_primitive(ctx, rval, &r, NO_HINT);
2044 if(FAILED(hres)) {
2045 jsval_release(l);
2046 return hres;
2047 }
2048
2049 if(is_string(l) && is_string(r)) {
2050 *ret = (jsstr_cmp(get_string(l), get_string(r)) < 0) ^ greater;
2051 jsstr_release(get_string(l));
2052 jsstr_release(get_string(r));
2053 return S_OK;
2054 }
2055
2056 hres = to_number(ctx, l, &ln);
2057 jsval_release(l);
2058 if(SUCCEEDED(hres))
2059 hres = to_number(ctx, r, &rn);
2060 jsval_release(r);
2061 if(FAILED(hres))
2062 return hres;
2063
2064 *ret = !isnan(ln) && !isnan(rn) && ((ln < rn) ^ greater);
2065 return S_OK;
2066 }
2067
2068 /* ECMA-262 3rd Edition 11.8.1 */
2069 static HRESULT interp_lt(exec_ctx_t *ctx)
2070 {
2071 jsval_t l, r;
2072 BOOL b;
2073 HRESULT hres;
2074
2075 r = stack_pop(ctx);
2076 l = stack_pop(ctx);
2077
2078 TRACE("%s < %s\n", debugstr_jsval(l), debugstr_jsval(r));
2079
2080 hres = less_eval(ctx->script, l, r, FALSE, &b);
2081 jsval_release(l);
2082 jsval_release(r);
2083 if(FAILED(hres))
2084 return hres;
2085
2086 return stack_push(ctx, jsval_bool(b));
2087 }
2088
2089 /* ECMA-262 3rd Edition 11.8.1 */
2090 static HRESULT interp_lteq(exec_ctx_t *ctx)
2091 {
2092 jsval_t l, r;
2093 BOOL b;
2094 HRESULT hres;
2095
2096 r = stack_pop(ctx);
2097 l = stack_pop(ctx);
2098
2099 TRACE("%s <= %s\n", debugstr_jsval(l), debugstr_jsval(r));
2100
2101 hres = less_eval(ctx->script, r, l, TRUE, &b);
2102 jsval_release(l);
2103 jsval_release(r);
2104 if(FAILED(hres))
2105 return hres;
2106
2107 return stack_push(ctx, jsval_bool(b));
2108 }
2109
2110 /* ECMA-262 3rd Edition 11.8.2 */
2111 static HRESULT interp_gt(exec_ctx_t *ctx)
2112 {
2113 jsval_t l, r;
2114 BOOL b;
2115 HRESULT hres;
2116
2117 r = stack_pop(ctx);
2118 l = stack_pop(ctx);
2119
2120 TRACE("%s > %s\n", debugstr_jsval(l), debugstr_jsval(r));
2121
2122 hres = less_eval(ctx->script, r, l, FALSE, &b);
2123 jsval_release(l);
2124 jsval_release(r);
2125 if(FAILED(hres))
2126 return hres;
2127
2128 return stack_push(ctx, jsval_bool(b));
2129 }
2130
2131 /* ECMA-262 3rd Edition 11.8.4 */
2132 static HRESULT interp_gteq(exec_ctx_t *ctx)
2133 {
2134 jsval_t l, r;
2135 BOOL b;
2136 HRESULT hres;
2137
2138 r = stack_pop(ctx);
2139 l = stack_pop(ctx);
2140
2141 TRACE("%s >= %s\n", debugstr_jsval(l), debugstr_jsval(r));
2142
2143 hres = less_eval(ctx->script, l, r, TRUE, &b);
2144 jsval_release(l);
2145 jsval_release(r);
2146 if(FAILED(hres))
2147 return hres;
2148
2149 return stack_push(ctx, jsval_bool(b));
2150 }
2151
2152 /* ECMA-262 3rd Edition 11.4.8 */
2153 static HRESULT interp_bneg(exec_ctx_t *ctx)
2154 {
2155 jsval_t v;
2156 INT i;
2157 HRESULT hres;
2158
2159 TRACE("\n");
2160
2161 v = stack_pop(ctx);
2162 hres = to_int32(ctx->script, v, &i);
2163 jsval_release(v);
2164 if(FAILED(hres))
2165 return hres;
2166
2167 return stack_push(ctx, jsval_number(~i));
2168 }
2169
2170 /* ECMA-262 3rd Edition 11.4.9 */
2171 static HRESULT interp_neg(exec_ctx_t *ctx)
2172 {
2173 jsval_t v;
2174 BOOL b;
2175 HRESULT hres;
2176
2177 TRACE("\n");
2178
2179 v = stack_pop(ctx);
2180 hres = to_boolean(v, &b);
2181 jsval_release(v);
2182 if(FAILED(hres))
2183 return hres;
2184
2185 return stack_push(ctx, jsval_bool(!b));
2186 }
2187
2188 /* ECMA-262 3rd Edition 11.7.1 */
2189 static HRESULT interp_lshift(exec_ctx_t *ctx)
2190 {
2191 DWORD r;
2192 INT l;
2193 HRESULT hres;
2194
2195 hres = stack_pop_uint(ctx, &r);
2196 if(FAILED(hres))
2197 return hres;
2198
2199 hres = stack_pop_int(ctx, &l);
2200 if(FAILED(hres))
2201 return hres;
2202
2203 return stack_push(ctx, jsval_number(l << (r&0x1f)));
2204 }
2205
2206 /* ECMA-262 3rd Edition 11.7.2 */
2207 static HRESULT interp_rshift(exec_ctx_t *ctx)
2208 {
2209 DWORD r;
2210 INT l;
2211 HRESULT hres;
2212
2213 hres = stack_pop_uint(ctx, &r);
2214 if(FAILED(hres))
2215 return hres;
2216
2217 hres = stack_pop_int(ctx, &l);
2218 if(FAILED(hres))
2219 return hres;
2220
2221 return stack_push(ctx, jsval_number(l >> (r&0x1f)));
2222 }
2223
2224 /* ECMA-262 3rd Edition 11.7.3 */
2225 static HRESULT interp_rshift2(exec_ctx_t *ctx)
2226 {
2227 DWORD r, l;
2228 HRESULT hres;
2229
2230 hres = stack_pop_uint(ctx, &r);
2231 if(FAILED(hres))
2232 return hres;
2233
2234 hres = stack_pop_uint(ctx, &l);
2235 if(FAILED(hres))
2236 return hres;
2237
2238 return stack_push(ctx, jsval_number(l >> (r&0x1f)));
2239 }
2240
2241 /* ECMA-262 3rd Edition 11.13.1 */
2242 static HRESULT interp_assign(exec_ctx_t *ctx)
2243 {
2244 IDispatch *disp;
2245 DISPID id;
2246 jsval_t v;
2247 HRESULT hres;
2248
2249 TRACE("\n");
2250
2251 v = stack_pop(ctx);
2252
2253 disp = stack_pop_objid(ctx, &id);
2254 if(!disp) {
2255 jsval_release(v);
2256 return throw_reference_error(ctx->script, JS_E_ILLEGAL_ASSIGN, NULL);
2257 }
2258
2259 hres = disp_propput(ctx->script, disp, id, v);
2260 IDispatch_Release(disp);
2261 if(FAILED(hres)) {
2262 jsval_release(v);
2263 return hres;
2264 }
2265
2266 return stack_push(ctx, v);
2267 }
2268
2269 /* JScript extension */
2270 static HRESULT interp_assign_call(exec_ctx_t *ctx)
2271 {
2272 const unsigned argc = get_op_uint(ctx, 0);
2273 IDispatch *disp;
2274 jsval_t v;
2275 DISPID id;
2276 HRESULT hres;
2277
2278 TRACE("%u\n", argc);
2279
2280 disp = stack_topn_objid(ctx, argc+1, &id);
2281 if(!disp)
2282 return throw_reference_error(ctx->script, JS_E_ILLEGAL_ASSIGN, NULL);
2283
2284 hres = disp_call(ctx->script, disp, id, DISPATCH_PROPERTYPUT, argc+1, stack_args(ctx, argc+1), NULL);
2285 if(FAILED(hres))
2286 return hres;
2287
2288 v = stack_pop(ctx);
2289 stack_popn(ctx, argc+2);
2290 return stack_push(ctx, v);
2291 }
2292
2293 static HRESULT interp_undefined(exec_ctx_t *ctx)
2294 {
2295 TRACE("\n");
2296
2297 return stack_push(ctx, jsval_undefined());
2298 }
2299
2300 static HRESULT interp_jmp(exec_ctx_t *ctx)
2301 {
2302 const unsigned arg = get_op_uint(ctx, 0);
2303
2304 TRACE("%u\n", arg);
2305
2306 ctx->ip = arg;
2307 return S_OK;
2308 }
2309
2310 static HRESULT interp_jmp_z(exec_ctx_t *ctx)
2311 {
2312 const unsigned arg = get_op_uint(ctx, 0);
2313 BOOL b;
2314 jsval_t v;
2315 HRESULT hres;
2316
2317 TRACE("\n");
2318
2319 v = stack_pop(ctx);
2320 hres = to_boolean(v, &b);
2321 jsval_release(v);
2322 if(FAILED(hres))
2323 return hres;
2324
2325 if(b)
2326 ctx->ip++;
2327 else
2328 ctx->ip = arg;
2329 return S_OK;
2330 }
2331
2332 static HRESULT interp_pop(exec_ctx_t *ctx)
2333 {
2334 const unsigned arg = get_op_uint(ctx, 0);
2335
2336 TRACE("%u\n", arg);
2337
2338 stack_popn(ctx, arg);
2339 return S_OK;
2340 }
2341
2342 static HRESULT interp_ret(exec_ctx_t *ctx)
2343 {
2344 TRACE("\n");
2345
2346 ctx->ip = -1;
2347 return S_OK;
2348 }
2349
2350 static HRESULT interp_setret(exec_ctx_t *ctx)
2351 {
2352 TRACE("\n");
2353
2354 jsval_release(ctx->ret);
2355 ctx->ret = stack_pop(ctx);
2356 return S_OK;
2357 }
2358
2359 typedef HRESULT (*op_func_t)(exec_ctx_t*);
2360
2361 static const op_func_t op_funcs[] = {
2362 #define X(x,a,b,c) interp_##x,
2363 OP_LIST
2364 #undef X
2365 };
2366
2367 static const unsigned op_move[] = {
2368 #define X(a,x,b,c) x,
2369 OP_LIST
2370 #undef X
2371 };
2372
2373 static HRESULT unwind_exception(exec_ctx_t *ctx)
2374 {
2375 except_frame_t *except_frame;
2376 jsval_t except_val;
2377 BSTR ident;
2378 HRESULT hres;
2379
2380 except_frame = ctx->except_frame;
2381 ctx->except_frame = except_frame->next;
2382
2383 assert(except_frame->stack_top <= ctx->top);
2384 stack_popn(ctx, ctx->top - except_frame->stack_top);
2385
2386 while(except_frame->scope != ctx->scope_chain)
2387 scope_pop(&ctx->scope_chain);
2388
2389 ctx->ip = except_frame->catch_off;
2390
2391 except_val = ctx->script->ei.val;
2392 ctx->script->ei.val = jsval_undefined();
2393 clear_ei(ctx->script);
2394
2395 ident = except_frame->ident;
2396 heap_free(except_frame);
2397
2398 if(ident) {
2399 jsdisp_t *scope_obj;
2400
2401 hres = create_dispex(ctx->script, NULL, NULL, &scope_obj);
2402 if(SUCCEEDED(hres)) {
2403 hres = jsdisp_propput_name(scope_obj, ident, except_val);
2404 if(FAILED(hres))
2405 jsdisp_release(scope_obj);
2406 }
2407 jsval_release(except_val);
2408 if(FAILED(hres))
2409 return hres;
2410
2411 hres = scope_push(ctx->scope_chain, scope_obj, to_disp(scope_obj), &ctx->scope_chain);
2412 jsdisp_release(scope_obj);
2413 }else {
2414 hres = stack_push(ctx, except_val);
2415 if(FAILED(hres))
2416 return hres;
2417
2418 hres = stack_push(ctx, jsval_bool(FALSE));
2419 }
2420
2421 return hres;
2422 }
2423
2424 static HRESULT enter_bytecode(script_ctx_t *ctx, bytecode_t *code, function_code_t *func, jsval_t *ret)
2425 {
2426 exec_ctx_t *exec_ctx = ctx->exec_ctx;
2427 except_frame_t *prev_except_frame;
2428 function_code_t *prev_func;
2429 unsigned prev_ip, prev_top;
2430 scope_chain_t *prev_scope;
2431 bytecode_t *prev_code;
2432 jsop_t op;
2433 HRESULT hres = S_OK;
2434
2435 TRACE("\n");
2436
2437 prev_top = exec_ctx->top;
2438 prev_scope = exec_ctx->scope_chain;
2439 prev_except_frame = exec_ctx->except_frame;
2440 prev_ip = exec_ctx->ip;
2441 prev_code = exec_ctx->code;
2442 prev_func = exec_ctx->func_code;
2443 exec_ctx->ip = func->instr_off;
2444 exec_ctx->except_frame = NULL;
2445 exec_ctx->code = code;
2446 exec_ctx->func_code = func;
2447
2448 while(exec_ctx->ip != -1) {
2449 op = code->instrs[exec_ctx->ip].op;
2450 hres = op_funcs[op](exec_ctx);
2451 if(FAILED(hres)) {
2452 TRACE("EXCEPTION %08x\n", hres);
2453
2454 if(!exec_ctx->except_frame)
2455 break;
2456
2457 hres = unwind_exception(exec_ctx);
2458 if(FAILED(hres))
2459 break;
2460 }else {
2461 exec_ctx->ip += op_move[op];
2462 }
2463 }
2464
2465 exec_ctx->ip = prev_ip;
2466 exec_ctx->except_frame = prev_except_frame;
2467 exec_ctx->code = prev_code;
2468 exec_ctx->func_code = prev_func;
2469
2470 if(FAILED(hres)) {
2471 while(exec_ctx->scope_chain != prev_scope)
2472 scope_pop(&exec_ctx->scope_chain);
2473 stack_popn(exec_ctx, exec_ctx->top-prev_top);
2474 return hres;
2475 }
2476
2477 assert(exec_ctx->top == prev_top+1 || exec_ctx->top == prev_top);
2478 assert(exec_ctx->scope_chain == prev_scope);
2479 assert(exec_ctx->top == prev_top);
2480
2481 *ret = exec_ctx->ret;
2482 exec_ctx->ret = jsval_undefined();
2483 return S_OK;
2484 }
2485
2486 HRESULT exec_source(exec_ctx_t *ctx, bytecode_t *code, function_code_t *func, BOOL from_eval, jsval_t *ret)
2487 {
2488 exec_ctx_t *prev_ctx;
2489 jsval_t val;
2490 unsigned i;
2491 HRESULT hres = S_OK;
2492
2493 for(i = 0; i < func->func_cnt; i++) {
2494 jsdisp_t *func_obj;
2495
2496 if(!func->funcs[i].name)
2497 continue;
2498
2499 hres = create_source_function(ctx->script, code, func->funcs+i, ctx->scope_chain, &func_obj);
2500 if(FAILED(hres))
2501 return hres;
2502
2503 hres = jsdisp_propput_name(ctx->var_disp, func->funcs[i].name, jsval_obj(func_obj));
2504 jsdisp_release(func_obj);
2505 if(FAILED(hres))
2506 return hres;
2507 }
2508
2509 for(i=0; i < func->var_cnt; i++) {
2510 if(!ctx->is_global || !lookup_global_members(ctx->script, func->variables[i], NULL)) {
2511 DISPID id = 0;
2512
2513 hres = jsdisp_get_id(ctx->var_disp, func->variables[i], fdexNameEnsure, &id);
2514 if(FAILED(hres))
2515 return hres;
2516 }
2517 }
2518
2519 prev_ctx = ctx->script->exec_ctx;
2520 ctx->script->exec_ctx = ctx;
2521
2522 hres = enter_bytecode(ctx->script, code, func, &val);
2523 assert(ctx->script->exec_ctx == ctx);
2524 ctx->script->exec_ctx = prev_ctx;
2525 if(FAILED(hres))
2526 return hres;
2527
2528 if(ret)
2529 *ret = val;
2530 else
2531 jsval_release(val);
2532 return S_OK;
2533 }