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