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