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