engine.c 59.1 KB
Newer Older
Jacek Caban's avatar
Jacek Caban committed
1
/*
2
 * Copyright 2008,2011 Jacek Caban for CodeWeavers
Jacek Caban's avatar
Jacek Caban committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

19 20 21
#include "config.h"
#include "wine/port.h"

22
#include <math.h>
23
#include <assert.h>
24

Jacek Caban's avatar
Jacek Caban committed
25 26 27 28 29 30 31
#include "jscript.h"
#include "engine.h"

#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(jscript);

32 33 34 35 36 37 38 39
static const WCHAR booleanW[] = {'b','o','o','l','e','a','n',0};
static const WCHAR functionW[] = {'f','u','n','c','t','i','o','n',0};
static const WCHAR numberW[] = {'n','u','m','b','e','r',0};
static const WCHAR objectW[] = {'o','b','j','e','c','t',0};
static const WCHAR stringW[] = {'s','t','r','i','n','g',0};
static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
static const WCHAR unknownW[] = {'u','n','k','n','o','w','n',0};

40 41 42 43 44 45 46 47 48
struct _except_frame_t {
    unsigned stack_top;
    scope_chain_t *scope;
    unsigned catch_off;
    BSTR ident;

    except_frame_t *next;
};

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v)
{
    if(!ctx->stack_size) {
        ctx->stack = heap_alloc(16*sizeof(VARIANT));
        if(!ctx->stack)
            return E_OUTOFMEMORY;
        ctx->stack_size = 16;
    }else if(ctx->stack_size == ctx->top) {
        VARIANT *new_stack;

        new_stack = heap_realloc(ctx->stack, ctx->stack_size*2*sizeof(VARIANT));
        if(!new_stack) {
            VariantClear(v);
            return E_OUTOFMEMORY;
        }

        ctx->stack = new_stack;
        ctx->stack_size *= 2;
    }

    ctx->stack[ctx->top++] = *v;
    return S_OK;
}

static HRESULT stack_push_bool(exec_ctx_t *ctx, BOOL b)
{
    VARIANT v;

    V_VT(&v) = VT_BOOL;
    V_BOOL(&v) = b ? VARIANT_TRUE : VARIANT_FALSE;
    return stack_push(ctx, &v);
}

82 83 84 85 86 87 88 89
static inline HRESULT stack_push_number(exec_ctx_t *ctx, double number)
{
    VARIANT v;

    num_set_val(&v, number);
    return stack_push(ctx, &v);
}

90 91 92 93 94 95 96 97 98
static inline HRESULT stack_push_int(exec_ctx_t *ctx, INT n)
{
    VARIANT v;

    V_VT(&v) = VT_I4;
    V_I4(&v) = n;
    return stack_push(ctx, &v);
}

99 100 101 102 103 104 105 106 107
static inline HRESULT stack_push_string(exec_ctx_t *ctx, const WCHAR *str)
{
    VARIANT v;

    V_VT(&v) = VT_BSTR;
    V_BSTR(&v) = SysAllocString(str);
    return V_BSTR(&v) ? stack_push(ctx, &v) : E_OUTOFMEMORY;
}

108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
static HRESULT stack_push_objid(exec_ctx_t *ctx, IDispatch *disp, DISPID id)
{
    VARIANT v;
    HRESULT hres;

    V_VT(&v) = VT_DISPATCH;
    V_DISPATCH(&v) = disp;
    hres = stack_push(ctx, &v);
    if(FAILED(hres))
        return hres;

    V_VT(&v) = VT_INT;
    V_INT(&v) = id;
    return stack_push(ctx, &v);
}

124 125
static inline VARIANT *stack_top(exec_ctx_t *ctx)
{
126
    assert(ctx->top);
127 128 129
    return ctx->stack + ctx->top-1;
}

130 131 132 133 134 135
static inline VARIANT *stack_topn(exec_ctx_t *ctx, unsigned n)
{
    assert(ctx->top > n);
    return ctx->stack + ctx->top-1-n;
}

136 137 138 139 140 141 142 143
static inline VARIANT *stack_args(exec_ctx_t *ctx, unsigned n)
{
    if(!n)
        return NULL;
    assert(ctx->top > n-1);
    return ctx->stack + ctx->top-n;
}

144 145 146 147 148 149 150 151 152 153 154 155
static inline VARIANT *stack_pop(exec_ctx_t *ctx)
{
    assert(ctx->top);
    return ctx->stack + --ctx->top;
}

static void stack_popn(exec_ctx_t *ctx, unsigned n)
{
    while(n--)
        VariantClear(stack_pop(ctx));
}

156
static HRESULT stack_pop_number(exec_ctx_t *ctx, double *r)
157 158 159 160 161
{
    VARIANT *v;
    HRESULT hres;

    v = stack_pop(ctx);
162
    hres = to_number(ctx->script, v, ctx->ei, r);
163
    VariantClear(v);
164
    return hres;
165 166
}

167 168 169 170 171 172 173
static HRESULT stack_pop_object(exec_ctx_t *ctx, IDispatch **r)
{
    VARIANT *v;
    HRESULT hres;

    v = stack_pop(ctx);
    if(V_VT(v) == VT_DISPATCH) {
174
        if(!V_DISPATCH(v))
175
            return throw_type_error(ctx->script, ctx->ei, JS_E_OBJECT_REQUIRED, NULL);
176 177 178 179
        *r = V_DISPATCH(v);
        return S_OK;
    }

180
    hres = to_object(ctx->script, v, r);
181 182 183 184
    VariantClear(v);
    return hres;
}

185 186
static inline HRESULT stack_pop_int(exec_ctx_t *ctx, INT *r)
{
187
    return to_int32(ctx->script, stack_pop(ctx), ctx->ei, r);
188 189
}

190 191
static inline HRESULT stack_pop_uint(exec_ctx_t *ctx, DWORD *r)
{
192
    return to_uint32(ctx->script, stack_pop(ctx), ctx->ei, r);
193 194
}

195 196 197 198 199 200 201 202
static inline IDispatch *stack_pop_objid(exec_ctx_t *ctx, DISPID *id)
{
    assert(V_VT(stack_top(ctx)) == VT_INT && V_VT(stack_topn(ctx, 1)) == VT_DISPATCH);

    *id = V_INT(stack_pop(ctx));
    return V_DISPATCH(stack_pop(ctx));
}

203
static inline IDispatch *stack_topn_objid(exec_ctx_t *ctx, unsigned n, DISPID *id)
204
{
205
    assert(V_VT(stack_topn(ctx, n)) == VT_INT && V_VT(stack_topn(ctx, n+1)) == VT_DISPATCH);
206

207 208
    *id = V_INT(stack_topn(ctx, n));
    return V_DISPATCH(stack_topn(ctx, n+1));
209 210
}

211 212 213 214
static void exprval_release(exprval_t *val)
{
    switch(val->type) {
    case EXPRVAL_VARIANT:
215 216
        if(V_VT(&val->u.var) != VT_EMPTY)
            VariantClear(&val->u.var);
217 218 219 220 221
        return;
    case EXPRVAL_IDREF:
        if(val->u.idref.disp)
            IDispatch_Release(val->u.idref.disp);
        return;
222
    case EXPRVAL_INVALID:
223
        return;
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
    }
}

/* ECMA-262 3rd Edition    8.7.1 */
static HRESULT exprval_value(script_ctx_t *ctx, exprval_t *val, jsexcept_t *ei, VARIANT *ret)
{
    V_VT(ret) = VT_EMPTY;

    switch(val->type) {
    case EXPRVAL_VARIANT:
        return VariantCopy(ret, &val->u.var);
    case EXPRVAL_IDREF:
        if(!val->u.idref.disp) {
            FIXME("throw ReferenceError\n");
            return E_FAIL;
        }

241
        return disp_propget(ctx, val->u.idref.disp, val->u.idref.id, ret, ei);
242
    case EXPRVAL_INVALID:
243
        assert(0);
244
    }
245 246 247

    ERR("type %d\n", val->type);
    return E_FAIL;
248 249 250 251 252 253 254 255 256 257 258 259 260
}

static HRESULT exprval_to_value(script_ctx_t *ctx, exprval_t *val, jsexcept_t *ei, VARIANT *ret)
{
    if(val->type == EXPRVAL_VARIANT) {
        *ret = val->u.var;
        V_VT(&val->u.var) = VT_EMPTY;
        return S_OK;
    }

    return exprval_value(ctx, val, ei, ret);
}

261 262 263 264 265 266 267 268 269 270
static void exprval_set_idref(exprval_t *val, IDispatch *disp, DISPID id)
{
    val->type = EXPRVAL_IDREF;
    val->u.idref.disp = disp;
    val->u.idref.id = id;

    if(disp)
        IDispatch_AddRef(disp);
}

271
HRESULT scope_push(scope_chain_t *scope, jsdisp_t *obj, scope_chain_t **ret)
272 273 274 275 276 277 278 279 280
{
    scope_chain_t *new_scope;

    new_scope = heap_alloc(sizeof(scope_chain_t));
    if(!new_scope)
        return E_OUTOFMEMORY;

    new_scope->ref = 1;

281
    jsdisp_addref(obj);
282 283 284 285 286 287 288 289 290 291 292 293 294
    new_scope->obj = obj;

    if(scope) {
        scope_addref(scope);
        new_scope->next = scope;
    }else {
        new_scope->next = NULL;
    }

    *ret = new_scope;
    return S_OK;
}

295 296 297 298 299 300 301 302 303
static void scope_pop(scope_chain_t **scope)
{
    scope_chain_t *tmp;

    tmp = *scope;
    *scope = tmp->next;
    scope_release(tmp);
}

304 305 306 307 308 309 310 311
void scope_release(scope_chain_t *scope)
{
    if(--scope->ref)
        return;

    if(scope->next)
        scope_release(scope->next);

Jacek Caban's avatar
Jacek Caban committed
312
    jsdisp_release(scope->obj);
313 314 315
    heap_free(scope);
}

316
HRESULT create_exec_ctx(script_ctx_t *script_ctx, IDispatch *this_obj, jsdisp_t *var_disp,
317
        scope_chain_t *scope, BOOL is_global, exec_ctx_t **ret)
318 319 320 321 322 323 324
{
    exec_ctx_t *ctx;

    ctx = heap_alloc_zero(sizeof(exec_ctx_t));
    if(!ctx)
        return E_OUTOFMEMORY;

325
    ctx->ref = 1;
326
    ctx->is_global = is_global;
327

328 329 330 331 332
    if(this_obj)
        ctx->this_obj = this_obj;
    else if(script_ctx->host_global)
        ctx->this_obj = script_ctx->host_global;
    else
333
        ctx->this_obj = to_disp(script_ctx->global);
334
    IDispatch_AddRef(ctx->this_obj);
335

336
    jsdisp_addref(var_disp);
337 338
    ctx->var_disp = var_disp;

339 340 341
    script_addref(script_ctx);
    ctx->script = script_ctx;

342 343 344 345 346
    if(scope) {
        scope_addref(scope);
        ctx->scope_chain = scope;
    }

347 348 349 350 351 352 353 354 355
    *ret = ctx;
    return S_OK;
}

void exec_release(exec_ctx_t *ctx)
{
    if(--ctx->ref)
        return;

356 357
    if(ctx->scope_chain)
        scope_release(ctx->scope_chain);
358
    if(ctx->var_disp)
Jacek Caban's avatar
Jacek Caban committed
359
        jsdisp_release(ctx->var_disp);
360 361
    if(ctx->this_obj)
        IDispatch_Release(ctx->this_obj);
362 363
    if(ctx->script)
        script_release(ctx->script);
364
    heap_free(ctx->stack);
365 366 367
    heap_free(ctx);
}

368
static HRESULT disp_get_id(script_ctx_t *ctx, IDispatch *disp, BSTR name, DWORD flags, DISPID *id)
369 370 371 372 373 374
{
    IDispatchEx *dispex;
    HRESULT hres;

    hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
    if(FAILED(hres)) {
375
        TRACE("using IDispatch\n");
376 377 378 379 380

        *id = 0;
        return IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, id);
    }

381
    *id = 0;
382
    hres = IDispatchEx_GetDispID(dispex, name, make_grfdex(ctx, flags|fdexNameCaseSensitive), id);
383 384 385 386
    IDispatchEx_Release(dispex);
    return hres;
}

387 388 389 390 391
static inline BOOL is_null(const VARIANT *v)
{
    return V_VT(v) == VT_NULL || (V_VT(v) == VT_DISPATCH && !V_DISPATCH(v));
}

392 393 394 395 396 397 398 399 400 401 402
static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, BOOL *ret)
{
    IObjectIdentity *identity;
    IUnknown *unk1, *unk2;
    HRESULT hres;

    if(disp1 == disp2) {
        *ret = TRUE;
        return S_OK;
    }

403 404
    if(!disp1 || !disp2) {
        *ret = FALSE;
405 406 407
        return S_OK;
    }

408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
    hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
    if(FAILED(hres))
        return hres;

    hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
    if(FAILED(hres)) {
        IUnknown_Release(unk1);
        return hres;
    }

    if(unk1 == unk2) {
        *ret = TRUE;
    }else {
        hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
        if(SUCCEEDED(hres)) {
            hres = IObjectIdentity_IsEqualObject(identity, unk2);
            IObjectIdentity_Release(identity);
            *ret = hres == S_OK;
        }else {
            *ret = FALSE;
        }
    }

    IUnknown_Release(unk1);
    IUnknown_Release(unk2);
    return S_OK;
}

/* ECMA-262 3rd Edition    11.9.6 */
437
static HRESULT equal2_values(VARIANT *lval, VARIANT *rval, BOOL *ret)
438 439 440 441
{
    TRACE("\n");

    if(V_VT(lval) != V_VT(rval)) {
442
        if(is_num_vt(V_VT(lval)) && is_num_vt(V_VT(rval)))
443
            *ret = num_val(lval) == num_val(rval);
444 445 446 447
        else if(is_null(lval))
            *ret = is_null(rval);
        else
            *ret = FALSE;
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
        return S_OK;
    }

    switch(V_VT(lval)) {
    case VT_EMPTY:
    case VT_NULL:
        *ret = VARIANT_TRUE;
        break;
    case VT_I4:
        *ret = V_I4(lval) == V_I4(rval);
        break;
    case VT_R8:
        *ret = V_R8(lval) == V_R8(rval);
        break;
    case VT_BSTR:
463
        if(!V_BSTR(lval))
464
            *ret = !SysStringLen(V_BSTR(rval));
465
        else if(!V_BSTR(rval))
466
            *ret = !SysStringLen(V_BSTR(lval));
467 468
        else
            *ret = !strcmpW(V_BSTR(lval), V_BSTR(rval));
469 470 471 472 473 474 475 476 477 478 479 480 481 482
        break;
    case VT_DISPATCH:
        return disp_cmp(V_DISPATCH(lval), V_DISPATCH(rval), ret);
    case VT_BOOL:
        *ret = !V_BOOL(lval) == !V_BOOL(rval);
        break;
    default:
        FIXME("unimplemented vt %d\n", V_VT(lval));
        return E_NOTIMPL;
    }

    return S_OK;
}

483 484 485 486 487 488 489 490
static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
{
    named_item_t *item;
    DISPID id;
    HRESULT hres;

    for(item = ctx->named_items; item; item = item->next) {
        if(item->flags & SCRIPTITEM_GLOBALMEMBERS) {
491
            hres = disp_get_id(ctx, item->disp, identifier, 0, &id);
492 493 494 495 496 497 498 499 500 501 502
            if(SUCCEEDED(hres)) {
                if(ret)
                    exprval_set_idref(ret, item->disp, id);
                return TRUE;
            }
        }
    }

    return FALSE;
}

503
/* ECMA-262 3rd Edition    10.1.4 */
504
static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
505
{
506
    scope_chain_t *scope;
507
    named_item_t *item;
508 509 510 511 512
    DISPID id = 0;
    HRESULT hres;

    TRACE("%s\n", debugstr_w(identifier));

513
    for(scope = ctx->exec_ctx->scope_chain; scope; scope = scope->next) {
514
        hres = jsdisp_get_id(scope->obj, identifier, 0, &id);
515 516 517 518
        if(SUCCEEDED(hres)) {
            exprval_set_idref(ret, to_disp(scope->obj), id);
            return S_OK;
        }
519
    }
520

521
    hres = jsdisp_get_id(ctx->global, identifier, 0, &id);
522
    if(SUCCEEDED(hres)) {
523
        exprval_set_idref(ret, to_disp(ctx->global), id);
524 525
        return S_OK;
    }
526

527
    for(item = ctx->named_items; item; item = item->next) {
528
        if((item->flags & SCRIPTITEM_ISVISIBLE) && !strcmpW(item->name, identifier)) {
529 530 531
            if(!item->disp) {
                IUnknown *unk;

532
                if(!ctx->site)
533 534
                    break;

535
                hres = IActiveScriptSite_GetItemInfo(ctx->site, identifier,
536 537 538 539 540 541 542 543 544 545 546 547 548 549
                                                     SCRIPTINFO_IUNKNOWN, &unk, NULL);
                if(FAILED(hres)) {
                    WARN("GetItemInfo failed: %08x\n", hres);
                    break;
                }

                hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp);
                IUnknown_Release(unk);
                if(FAILED(hres)) {
                    WARN("object does not implement IDispatch\n");
                    break;
                }
            }

550 551 552 553 554 555 556 557
            ret->type = EXPRVAL_VARIANT;
            V_VT(&ret->u.var) = VT_DISPATCH;
            V_DISPATCH(&ret->u.var) = item->disp;
            IDispatch_AddRef(item->disp);
            return S_OK;
        }
    }

558
    if(lookup_global_members(ctx, identifier, ret))
559 560
        return S_OK;

561 562
    ret->type = EXPRVAL_INVALID;
    return S_OK;
563 564
}

565
static inline BSTR get_op_bstr(exec_ctx_t *ctx, int i){
566
    return ctx->code->instrs[ctx->ip].u.arg[i].bstr;
567 568
}

569
static inline unsigned get_op_uint(exec_ctx_t *ctx, int i){
570
    return ctx->code->instrs[ctx->ip].u.arg[i].uint;
571 572
}

573
static inline unsigned get_op_int(exec_ctx_t *ctx, int i){
574
    return ctx->code->instrs[ctx->ip].u.arg[i].lng;
575 576
}

577
static inline const WCHAR *get_op_str(exec_ctx_t *ctx, int i){
578
    return ctx->code->instrs[ctx->ip].u.arg[i].str;
579 580 581
}

static inline double get_op_double(exec_ctx_t *ctx){
582
    return ctx->code->instrs[ctx->ip].u.dbl;
583 584
}

585
/* ECMA-262 3rd Edition    12.2 */
586
static HRESULT interp_var_set(exec_ctx_t *ctx)
587
{
588
    const BSTR name = get_op_bstr(ctx, 0);
589
    VARIANT *v;
590 591
    HRESULT hres;

592
    TRACE("%s\n", debugstr_w(name));
593

594
    v = stack_pop(ctx);
595
    hres = jsdisp_propput_name(ctx->var_disp, name, v, ctx->ei);
596 597
    VariantClear(v);
    return hres;
Jacek Caban's avatar
Jacek Caban committed
598 599
}

600 601 602
/* ECMA-262 3rd Edition    12.6.4 */
static HRESULT interp_forin(exec_ctx_t *ctx)
{
603
    const HRESULT arg = get_op_uint(ctx, 0);
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
    IDispatch *var_obj, *obj = NULL;
    IDispatchEx *dispex;
    DISPID id, var_id;
    BSTR name = NULL;
    VARIANT *val;
    HRESULT hres;

    TRACE("\n");

    val = stack_pop(ctx);

    assert(V_VT(stack_top(ctx)) == VT_I4);
    id = V_I4(stack_top(ctx));

    var_obj = stack_topn_objid(ctx, 1, &var_id);
    if(!var_obj) {
        FIXME("invalid ref\n");
        VariantClear(val);
        return E_FAIL;
    }

    if(V_VT(stack_topn(ctx, 3)) == VT_DISPATCH)
        obj = V_DISPATCH(stack_topn(ctx, 3));

    if(obj) {
        hres = IDispatch_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
        if(SUCCEEDED(hres)) {
            hres = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, id, &id);
            if(hres == S_OK)
                hres = IDispatchEx_GetMemberName(dispex, id, &name);
            IDispatchEx_Release(dispex);
            if(FAILED(hres)) {
                VariantClear(val);
                return hres;
            }
        }else {
            TRACE("No IDispatchEx\n");
        }
    }

    if(name) {
        VARIANT v;

        VariantClear(val);

        V_I4(stack_top(ctx)) = id;

        V_VT(&v) = VT_BSTR;
        V_BSTR(&v) = name;
653
        hres = disp_propput(ctx->script, var_obj, var_id, &v, ctx->ei);
654 655 656 657 658 659 660 661 662 663 664 665 666
        SysFreeString(name);
        if(FAILED(hres))
            return hres;

        ctx->ip++;
    }else {
        stack_popn(ctx, 4);
        ctx->ip = arg;
        return stack_push(ctx, val);
    }
    return S_OK;
}

667
/* ECMA-262 3rd Edition    12.10 */
668
static HRESULT interp_push_scope(exec_ctx_t *ctx)
669 670 671 672 673 674 675 676 677
{
    IDispatch *disp;
    jsdisp_t *obj;
    VARIANT *v;
    HRESULT hres;

    TRACE("\n");

    v = stack_pop(ctx);
678
    hres = to_object(ctx->script, v, &disp);
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695
    VariantClear(v);
    if(FAILED(hres))
        return hres;

    obj = to_jsdisp(disp);
    if(!obj) {
        IDispatch_Release(disp);
        FIXME("disp is not jsdisp\n");
        return E_NOTIMPL;
    }

    hres = scope_push(ctx->scope_chain, obj, &ctx->scope_chain);
    jsdisp_release(obj);
    return hres;
}

/* ECMA-262 3rd Edition    12.10 */
696
static HRESULT interp_pop_scope(exec_ctx_t *ctx)
697 698 699 700 701 702 703
{
    TRACE("\n");

    scope_pop(&ctx->scope_chain);
    return S_OK;
}

704 705 706
/* ECMA-262 3rd Edition    12.13 */
static HRESULT interp_case(exec_ctx_t *ctx)
{
707
    const unsigned arg = get_op_uint(ctx, 0);
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728
    VARIANT *v;
    BOOL b;
    HRESULT hres;

    TRACE("\n");

    v = stack_pop(ctx);
    hres = equal2_values(stack_top(ctx), v, &b);
    VariantClear(v);
    if(FAILED(hres))
        return hres;

    if(b) {
        stack_popn(ctx, 1);
        ctx->ip = arg;
    }else {
        ctx->ip++;
    }
    return S_OK;
}

729
/* ECMA-262 3rd Edition    12.13 */
730
static HRESULT interp_throw(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
731
{
732 733
    TRACE("\n");

734
    ctx->ei->var = *stack_pop(ctx);
735
    return DISP_E_EXCEPTION;
Jacek Caban's avatar
Jacek Caban committed
736 737
}

738
static HRESULT interp_throw_ref(exec_ctx_t *ctx)
739
{
740
    const HRESULT arg = get_op_uint(ctx, 0);
741 742 743

    TRACE("%08x\n", arg);

744
    return throw_reference_error(ctx->script, ctx->ei, arg, NULL);
745 746
}

747 748
static HRESULT interp_throw_type(exec_ctx_t *ctx)
{
749
    const HRESULT hres = get_op_uint(ctx, 0);
750
    const WCHAR *str = get_op_str(ctx, 1);
751 752 753

    TRACE("%08x %s\n", hres, debugstr_w(str));

754
    return throw_type_error(ctx->script, ctx->ei, hres, str);
755 756
}

757 758 759
/* ECMA-262 3rd Edition    12.14 */
static HRESULT interp_push_except(exec_ctx_t *ctx)
{
760
    const unsigned arg1 = get_op_uint(ctx, 0);
761
    const BSTR arg2 = get_op_bstr(ctx, 1);
762 763 764 765 766 767 768 769 770 771 772 773 774
    except_frame_t *except;
    unsigned stack_top;

    TRACE("\n");

    stack_top = ctx->top;

    if(!arg2) {
        HRESULT hres;

        hres = stack_push_bool(ctx, TRUE);
        if(FAILED(hres))
            return hres;
775 776 777
        hres = stack_push_bool(ctx, TRUE);
        if(FAILED(hres))
            return hres;
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822
    }

    except = heap_alloc(sizeof(*except));
    if(!except)
        return E_OUTOFMEMORY;

    except->stack_top = stack_top;
    except->scope = ctx->scope_chain;
    except->catch_off = arg1;
    except->ident = arg2;
    except->next = ctx->except_frame;
    ctx->except_frame = except;
    return S_OK;
}

/* ECMA-262 3rd Edition    12.14 */
static HRESULT interp_pop_except(exec_ctx_t *ctx)
{
    except_frame_t *except;

    TRACE("\n");

    except = ctx->except_frame;
    assert(except != NULL);

    ctx->except_frame = except->next;
    heap_free(except);
    return S_OK;
}

/* ECMA-262 3rd Edition    12.14 */
static HRESULT interp_end_finally(exec_ctx_t *ctx)
{
    VARIANT *v;

    TRACE("\n");

    v = stack_pop(ctx);

    assert(V_VT(stack_top(ctx)) == VT_BOOL);
    if(!V_BOOL(stack_top(ctx))) {
        TRACE("passing exception\n");

        VariantClear(v);
        stack_popn(ctx, 1);
823
        ctx->ei->var = *stack_pop(ctx);
824 825 826
        return DISP_E_EXCEPTION;
    }

827 828
    stack_popn(ctx, 2);
    return stack_push(ctx, v);
829 830
}

831
/* ECMA-262 3rd Edition    13 */
832
static HRESULT interp_func(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
833
{
834
    unsigned func_idx = get_op_uint(ctx, 0);
835 836
    jsdisp_t *dispex;
    VARIANT v;
837 838
    HRESULT hres;

839 840
    TRACE("%d\n", func_idx);

841
    hres = create_source_function(ctx->script, ctx->code, ctx->func_code->funcs+func_idx,
842
            ctx->scope_chain, &dispex);
843 844
    if(FAILED(hres))
        return hres;
845

846 847
    var_set_jsdisp(&v, dispex);
    return stack_push(ctx, &v);
Jacek Caban's avatar
Jacek Caban committed
848 849
}

850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
/* ECMA-262 3rd Edition    11.2.1 */
static HRESULT interp_array(exec_ctx_t *ctx)
{
    VARIANT v, *namev;
    IDispatch *obj;
    DISPID id;
    BSTR name;
    HRESULT hres;

    TRACE("\n");

    namev = stack_pop(ctx);

    hres = stack_pop_object(ctx, &obj);
    if(FAILED(hres)) {
        VariantClear(namev);
        return hres;
    }

869
    hres = to_string(ctx->script, namev, ctx->ei, &name);
870
    VariantClear(namev);
871 872 873 874 875
    if(FAILED(hres)) {
        IDispatch_Release(obj);
        return hres;
    }

876
    hres = disp_get_id(ctx->script, obj, name, 0, &id);
877 878
    SysFreeString(name);
    if(SUCCEEDED(hres)) {
879
        hres = disp_propget(ctx->script, obj, id, &v, ctx->ei);
880 881 882 883 884 885 886 887 888 889 890
    }else if(hres == DISP_E_UNKNOWNNAME) {
        V_VT(&v) = VT_EMPTY;
        hres = S_OK;
    }
    IDispatch_Release(obj);
    if(FAILED(hres))
        return hres;

    return stack_push(ctx, &v);
}

891 892 893
/* ECMA-262 3rd Edition    11.2.1 */
static HRESULT interp_member(exec_ctx_t *ctx)
{
894
    const BSTR arg = get_op_bstr(ctx, 0);
895 896 897 898 899 900 901 902 903 904 905
    IDispatch *obj;
    VARIANT v;
    DISPID id;
    HRESULT hres;

    TRACE("\n");

    hres = stack_pop_object(ctx, &obj);
    if(FAILED(hres))
        return hres;

906
    hres = disp_get_id(ctx->script, obj, arg, 0, &id);
907
    if(SUCCEEDED(hres)) {
908
        V_VT(&v) = VT_EMPTY;
909
        hres = disp_propget(ctx->script, obj, id, &v, ctx->ei);
910 911 912 913 914 915 916 917 918 919 920
    }else if(hres == DISP_E_UNKNOWNNAME) {
        V_VT(&v) = VT_EMPTY;
        hres = S_OK;
    }
    IDispatch_Release(obj);
    if(FAILED(hres))
        return hres;

    return stack_push(ctx, &v);
}

921 922 923
/* ECMA-262 3rd Edition    11.2.1 */
static HRESULT interp_memberid(exec_ctx_t *ctx)
{
924
    const unsigned arg = get_op_uint(ctx, 0);
925 926 927 928 929 930
    VARIANT *objv, *namev;
    IDispatch *obj;
    BSTR name;
    DISPID id;
    HRESULT hres;

931
    TRACE("%x\n", arg);
932 933 934 935

    namev = stack_pop(ctx);
    objv = stack_pop(ctx);

936
    hres = to_object(ctx->script, objv, &obj);
937 938
    VariantClear(objv);
    if(SUCCEEDED(hres)) {
939
        hres = to_string(ctx->script, namev, ctx->ei, &name);
940 941 942 943 944 945 946
        if(FAILED(hres))
            IDispatch_Release(obj);
    }
    VariantClear(namev);
    if(FAILED(hres))
        return hres;

947
    hres = disp_get_id(ctx->script, obj, name, arg, &id);
948 949 950
    SysFreeString(name);
    if(FAILED(hres)) {
        IDispatch_Release(obj);
951 952 953 954 955 956
        if(hres == DISP_E_UNKNOWNNAME && !(arg & fdexNameEnsure)) {
            obj = NULL;
            id = JS_E_INVALID_PROPERTY;
        }else {
            return hres;
        }
957 958 959 960 961
    }

    return stack_push_objid(ctx, obj, id);
}

962 963 964 965 966 967 968 969 970 971
/* ECMA-262 3rd Edition    11.2.1 */
static HRESULT interp_refval(exec_ctx_t *ctx)
{
    IDispatch *disp;
    VARIANT v;
    DISPID id;
    HRESULT hres;

    TRACE("\n");

972
    disp = stack_topn_objid(ctx, 0, &id);
973
    if(!disp)
974
        return throw_reference_error(ctx->script, ctx->ei, JS_E_ILLEGAL_ASSIGN, NULL);
975

976
    hres = disp_propget(ctx->script, disp, id, &v, ctx->ei);
977 978 979 980 981 982
    if(FAILED(hres))
        return hres;

    return stack_push(ctx, &v);
}

983
/* ECMA-262 3rd Edition    11.2.2 */
984
static HRESULT interp_new(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
985
{
986
    const unsigned arg = get_op_uint(ctx, 0);
987
    VARIANT *constr, v;
988 989
    HRESULT hres;

990
    TRACE("%d\n", arg);
991

992
    constr = stack_topn(ctx, arg);
993

994 995
    /* NOTE: Should use to_object here */

996
    if(V_VT(constr) == VT_NULL)
997
        return throw_type_error(ctx->script, ctx->ei, JS_E_OBJECT_EXPECTED, NULL);
998
    else if(V_VT(constr) != VT_DISPATCH)
999
        return throw_type_error(ctx->script, ctx->ei, JS_E_INVALID_ACTION, NULL);
1000
    else if(!V_DISPATCH(constr))
1001
        return throw_type_error(ctx->script, ctx->ei, JS_E_INVALID_PROPERTY, NULL);
1002

1003
    hres = disp_call_value(ctx->script, V_DISPATCH(constr), NULL, DISPATCH_CONSTRUCT, arg, stack_args(ctx, arg), &v, ctx->ei);
1004 1005 1006
    if(FAILED(hres))
        return hres;

1007 1008
    stack_popn(ctx, arg+1);
    return stack_push(ctx, &v);
Jacek Caban's avatar
Jacek Caban committed
1009 1010
}

Jacek Caban's avatar
Jacek Caban committed
1011
/* ECMA-262 3rd Edition    11.2.3 */
1012
static HRESULT interp_call(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
1013
{
1014
    const unsigned argn = get_op_uint(ctx, 0);
1015
    const int do_ret = get_op_int(ctx, 1);
1016
    VARIANT v, *objv;
1017 1018
    HRESULT hres;

1019
    TRACE("%d %d\n", argn, do_ret);
1020

1021 1022
    objv = stack_topn(ctx, argn);
    if(V_VT(objv) != VT_DISPATCH)
1023
        return throw_type_error(ctx->script, ctx->ei, JS_E_INVALID_PROPERTY, NULL);
1024

1025
    hres = disp_call_value(ctx->script, V_DISPATCH(objv), NULL, DISPATCH_METHOD, argn, stack_args(ctx, argn),
1026
            do_ret ? &v : NULL, ctx->ei);
1027 1028 1029
    if(FAILED(hres))
        return hres;

1030 1031 1032
    stack_popn(ctx, argn+1);
    return do_ret ? stack_push(ctx, &v) : S_OK;

Jacek Caban's avatar
Jacek Caban committed
1033 1034
}

1035 1036 1037
/* ECMA-262 3rd Edition    11.2.3 */
static HRESULT interp_call_member(exec_ctx_t *ctx)
{
1038
    const unsigned argn = get_op_uint(ctx, 0);
1039
    const int do_ret = get_op_int(ctx, 1);
1040 1041 1042 1043 1044 1045 1046 1047 1048
    IDispatch *obj;
    VARIANT v;
    DISPID id;
    HRESULT hres;

    TRACE("%d %d\n", argn, do_ret);

    obj = stack_topn_objid(ctx, argn, &id);
    if(!obj)
1049
        return throw_type_error(ctx->script, ctx->ei, id, NULL);
1050

1051
    hres = disp_call(ctx->script, obj, id, DISPATCH_METHOD, argn, stack_args(ctx, argn), do_ret ? &v : NULL, ctx->ei);
1052 1053 1054 1055 1056 1057 1058 1059
    if(FAILED(hres))
        return hres;

    stack_popn(ctx, argn+2);
    return do_ret ? stack_push(ctx, &v) : S_OK;

}

Jacek Caban's avatar
Jacek Caban committed
1060
/* ECMA-262 3rd Edition    11.1.1 */
1061
static HRESULT interp_this(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
1062
{
1063 1064
    VARIANT v;

1065 1066
    TRACE("\n");

1067 1068 1069 1070
    V_VT(&v) = VT_DISPATCH;
    V_DISPATCH(&v) = ctx->this_obj;
    IDispatch_AddRef(ctx->this_obj);
    return stack_push(ctx, &v);
Jacek Caban's avatar
Jacek Caban committed
1071 1072
}

1073 1074 1075
/* ECMA-262 3rd Edition    10.1.4 */
static HRESULT interp_ident(exec_ctx_t *ctx)
{
1076
    const BSTR arg = get_op_bstr(ctx, 0);
1077 1078 1079 1080 1081 1082
    exprval_t exprval;
    VARIANT v;
    HRESULT hres;

    TRACE("%s\n", debugstr_w(arg));

1083
    hres = identifier_eval(ctx->script, arg, &exprval);
1084 1085 1086
    if(FAILED(hres))
        return hres;

1087
    if(exprval.type == EXPRVAL_INVALID)
1088
        return throw_type_error(ctx->script, ctx->ei, JS_E_UNDEFINED_VARIABLE, arg);
1089

1090
    hres = exprval_to_value(ctx->script, &exprval, ctx->ei, &v);
1091 1092 1093 1094 1095 1096 1097
    exprval_release(&exprval);
    if(FAILED(hres))
        return hres;

    return stack_push(ctx, &v);
}

1098 1099 1100
/* ECMA-262 3rd Edition    10.1.4 */
static HRESULT interp_identid(exec_ctx_t *ctx)
{
1101
    const BSTR arg = get_op_bstr(ctx, 0);
1102
    const unsigned flags = get_op_uint(ctx, 1);
1103 1104 1105
    exprval_t exprval;
    HRESULT hres;

1106
    TRACE("%s %x\n", debugstr_w(arg), flags);
1107

1108
    hres = identifier_eval(ctx->script, arg, &exprval);
1109 1110 1111
    if(FAILED(hres))
        return hres;

1112 1113 1114
    if(exprval.type == EXPRVAL_INVALID && (flags & fdexNameEnsure)) {
        DISPID id;

1115
        hres = jsdisp_get_id(ctx->script->global, arg, fdexNameEnsure, &id);
1116 1117 1118
        if(FAILED(hres))
            return hres;

1119
        exprval_set_idref(&exprval, to_disp(ctx->script->global), id);
1120 1121
    }

1122 1123 1124
    if(exprval.type != EXPRVAL_IDREF) {
        WARN("invalid ref\n");
        exprval_release(&exprval);
1125
        return stack_push_objid(ctx, NULL, JS_E_OBJECT_EXPECTED);
1126 1127 1128 1129 1130
    }

    return stack_push_objid(ctx, exprval.u.idref.disp, exprval.u.idref.id);
}

1131
/* ECMA-262 3rd Edition    7.8.1 */
1132
static HRESULT interp_null(exec_ctx_t *ctx)
1133 1134 1135 1136 1137 1138 1139 1140 1141
{
    VARIANT v;

    TRACE("\n");

    V_VT(&v) = VT_NULL;
    return stack_push(ctx, &v);
}

1142
/* ECMA-262 3rd Edition    7.8.2 */
1143
static HRESULT interp_bool(exec_ctx_t *ctx)
1144
{
1145
    const int arg = get_op_int(ctx, 0);
1146 1147 1148 1149 1150 1151

    TRACE("%s\n", arg ? "true" : "false");

    return stack_push_bool(ctx, arg);
}

1152
/* ECMA-262 3rd Edition    7.8.3 */
1153
static HRESULT interp_int(exec_ctx_t *ctx)
1154
{
1155
    const int arg = get_op_int(ctx, 0);
1156 1157 1158 1159 1160 1161 1162 1163 1164
    VARIANT v;

    TRACE("%d\n", arg);

    V_VT(&v) = VT_I4;
    V_I4(&v) = arg;
    return stack_push(ctx, &v);
}

1165
/* ECMA-262 3rd Edition    7.8.3 */
1166
static HRESULT interp_double(exec_ctx_t *ctx)
1167
{
1168
    const double arg = get_op_double(ctx);
1169 1170 1171

    TRACE("%lf\n", arg);

1172
    return stack_push_number(ctx, arg);
1173 1174
}

1175
/* ECMA-262 3rd Edition    7.8.4 */
1176
static HRESULT interp_str(exec_ctx_t *ctx)
1177
{
1178
    const WCHAR *str = get_op_str(ctx, 0);
1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
    VARIANT v;

    TRACE("%s\n", debugstr_w(str));

    V_VT(&v) = VT_BSTR;
    V_BSTR(&v) = SysAllocString(str);
    if(!V_BSTR(&v))
        return E_OUTOFMEMORY;

    return stack_push(ctx, &v);
}

1191
/* ECMA-262 3rd Edition    7.8 */
1192
static HRESULT interp_regexp(exec_ctx_t *ctx)
1193
{
1194
    const WCHAR *source = get_op_str(ctx, 0);
1195
    const unsigned flags = get_op_uint(ctx, 1);
1196 1197 1198 1199 1200 1201
    jsdisp_t *regexp;
    VARIANT v;
    HRESULT hres;

    TRACE("%s %x\n", debugstr_w(source), flags);

1202
    hres = create_regexp(ctx->script, source, strlenW(source), flags, &regexp);
1203 1204 1205 1206 1207 1208 1209
    if(FAILED(hres))
        return hres;

    var_set_jsdisp(&v, regexp);
    return stack_push(ctx, &v);
}

1210
/* ECMA-262 3rd Edition    11.1.4 */
1211
static HRESULT interp_carray(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
1212
{
1213
    const unsigned arg = get_op_uint(ctx, 0);
1214
    jsdisp_t *array;
1215 1216
    VARIANT *v, r;
    unsigned i;
1217 1218
    HRESULT hres;

1219
    TRACE("%u\n", arg);
1220

1221
    hres = create_array(ctx->script, arg, &array);
1222 1223 1224
    if(FAILED(hres))
        return hres;

1225 1226 1227
    i = arg;
    while(i--) {
        v = stack_pop(ctx);
1228
        hres = jsdisp_propput_idx(array, i, v, ctx->ei);
1229 1230 1231 1232 1233
        VariantClear(v);
        if(FAILED(hres)) {
            jsdisp_release(array);
            return hres;
        }
1234 1235
    }

1236 1237
    var_set_jsdisp(&r, array);
    return stack_push(ctx, &r);
Jacek Caban's avatar
Jacek Caban committed
1238 1239
}

1240
/* ECMA-262 3rd Edition    11.1.5 */
1241
static HRESULT interp_new_obj(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
1242
{
1243
    jsdisp_t *obj;
1244
    VARIANT v;
1245 1246 1247 1248
    HRESULT hres;

    TRACE("\n");

1249
    hres = create_object(ctx->script, NULL, &obj);
1250 1251 1252
    if(FAILED(hres))
        return hres;

1253 1254 1255
    var_set_jsdisp(&v, obj);
    return stack_push(ctx, &v);
}
1256

1257
/* ECMA-262 3rd Edition    11.1.5 */
1258
static HRESULT interp_obj_prop(exec_ctx_t *ctx)
1259
{
1260
    const BSTR name = get_op_bstr(ctx, 0);
1261 1262 1263
    jsdisp_t *obj;
    VARIANT *v;
    HRESULT hres;
1264

1265
    TRACE("%s\n", debugstr_w(name));
1266

1267
    v = stack_pop(ctx);
1268

1269 1270
    assert(V_VT(stack_top(ctx)) == VT_DISPATCH);
    obj = as_jsdisp(V_DISPATCH(stack_top(ctx)));
1271

1272
    hres = jsdisp_propput_name(obj, name, v, ctx->ei);
1273 1274
    VariantClear(v);
    return hres;
Jacek Caban's avatar
Jacek Caban committed
1275 1276
}

1277
/* ECMA-262 3rd Edition    11.11 */
1278
static HRESULT interp_cnd_nz(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
1279
{
1280
    const unsigned arg = get_op_uint(ctx, 0);
1281 1282 1283 1284 1285
    VARIANT_BOOL b;
    HRESULT hres;

    TRACE("\n");

1286
    hres = to_boolean(stack_top(ctx), &b);
1287 1288 1289
    if(FAILED(hres))
        return hres;

1290 1291 1292 1293 1294
    if(b) {
        ctx->ip = arg;
    }else {
        stack_popn(ctx, 1);
        ctx->ip++;
1295 1296
    }
    return S_OK;
Jacek Caban's avatar
Jacek Caban committed
1297 1298
}

1299
/* ECMA-262 3rd Edition    11.11 */
1300
static HRESULT interp_cnd_z(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
1301
{
1302
    const unsigned arg = get_op_uint(ctx, 0);
1303 1304 1305 1306 1307
    VARIANT_BOOL b;
    HRESULT hres;

    TRACE("\n");

1308
    hres = to_boolean(stack_top(ctx), &b);
1309 1310 1311
    if(FAILED(hres))
        return hres;

1312 1313 1314 1315 1316
    if(b) {
        stack_popn(ctx, 1);
        ctx->ip++;
    }else {
        ctx->ip = arg;
1317 1318
    }
    return S_OK;
Jacek Caban's avatar
Jacek Caban committed
1319 1320
}

1321
/* ECMA-262 3rd Edition    11.10 */
1322
static HRESULT interp_or(exec_ctx_t *ctx)
1323
{
1324 1325
    INT l, r;
    HRESULT hres;
1326 1327 1328

    TRACE("\n");

1329 1330 1331 1332 1333 1334 1335 1336 1337
    hres = stack_pop_int(ctx, &r);
    if(FAILED(hres))
        return hres;

    hres = stack_pop_int(ctx, &l);
    if(FAILED(hres))
        return hres;

    return stack_push_int(ctx, l|r);
Jacek Caban's avatar
Jacek Caban committed
1338 1339
}

1340
/* ECMA-262 3rd Edition    11.10 */
1341
static HRESULT interp_xor(exec_ctx_t *ctx)
1342
{
1343 1344
    INT l, r;
    HRESULT hres;
1345 1346 1347

    TRACE("\n");

1348 1349 1350 1351 1352 1353 1354 1355 1356
    hres = stack_pop_int(ctx, &r);
    if(FAILED(hres))
        return hres;

    hres = stack_pop_int(ctx, &l);
    if(FAILED(hres))
        return hres;

    return stack_push_int(ctx, l^r);
Jacek Caban's avatar
Jacek Caban committed
1357 1358
}

1359
/* ECMA-262 3rd Edition    11.10 */
1360
static HRESULT interp_and(exec_ctx_t *ctx)
1361
{
1362 1363
    INT l, r;
    HRESULT hres;
1364 1365 1366

    TRACE("\n");

1367 1368 1369 1370 1371 1372 1373 1374 1375
    hres = stack_pop_int(ctx, &r);
    if(FAILED(hres))
        return hres;

    hres = stack_pop_int(ctx, &l);
    if(FAILED(hres))
        return hres;

    return stack_push_int(ctx, l&r);
Jacek Caban's avatar
Jacek Caban committed
1376 1377
}

Jacek Caban's avatar
Jacek Caban committed
1378
/* ECMA-262 3rd Edition    11.8.6 */
1379
static HRESULT interp_instanceof(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
1380
{
1381
    jsdisp_t *obj, *iter, *tmp = NULL;
1382 1383
    VARIANT prot, *v;
    BOOL ret = FALSE;
1384 1385 1386 1387
    HRESULT hres;

    static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0};

1388 1389 1390
    v = stack_pop(ctx);
    if(V_VT(v) != VT_DISPATCH || !V_DISPATCH(v)) {
        VariantClear(v);
1391
        return throw_type_error(ctx->script, ctx->ei, JS_E_FUNCTION_EXPECTED, NULL);
1392
    }
1393

1394 1395
    obj = iface_to_jsdisp((IUnknown*)V_DISPATCH(v));
    IDispatch_Release(V_DISPATCH(v));
1396
    if(!obj) {
1397
        FIXME("non-jsdisp objects not supported\n");
1398 1399 1400 1401
        return E_FAIL;
    }

    if(is_class(obj, JSCLASS_FUNCTION)) {
1402
        hres = jsdisp_propget_name(obj, prototypeW, &prot, ctx->ei);
1403
    }else {
1404
        hres = throw_type_error(ctx->script, ctx->ei, JS_E_FUNCTION_EXPECTED, NULL);
1405 1406 1407 1408 1409
    }
    jsdisp_release(obj);
    if(FAILED(hres))
        return hres;

1410 1411 1412 1413 1414 1415 1416
    v = stack_pop(ctx);

    if(V_VT(&prot) == VT_DISPATCH) {
        if(V_VT(v) == VT_DISPATCH)
            tmp = iface_to_jsdisp((IUnknown*)V_DISPATCH(v));
        for(iter = tmp; !ret && iter; iter = iter->prototype) {
            hres = disp_cmp(V_DISPATCH(&prot), to_disp(iter), &ret);
1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427
            if(FAILED(hres))
                break;
        }

        if(tmp)
            jsdisp_release(tmp);
    }else {
        FIXME("prototype is not an object\n");
        hres = E_FAIL;
    }

1428 1429
    VariantClear(&prot);
    VariantClear(v);
1430 1431 1432
    if(FAILED(hres))
        return hres;

1433
    return stack_push_bool(ctx, ret);
Jacek Caban's avatar
Jacek Caban committed
1434 1435
}

Jacek Caban's avatar
Jacek Caban committed
1436
/* ECMA-262 3rd Edition    11.8.7 */
1437
static HRESULT interp_in(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
1438
{
1439 1440 1441
    VARIANT *obj, *v;
    DISPID id = 0;
    BOOL ret;
1442 1443 1444
    BSTR str;
    HRESULT hres;

1445
    TRACE("\n");
1446

1447 1448 1449 1450 1451 1452
    obj = stack_pop(ctx);
    v = stack_pop(ctx);

    if(V_VT(obj) != VT_DISPATCH || !V_DISPATCH(obj)) {
        VariantClear(obj);
        VariantClear(v);
1453
        return throw_type_error(ctx->script, ctx->ei, JS_E_OBJECT_EXPECTED, NULL);
1454 1455
    }

1456
    hres = to_string(ctx->script, v, ctx->ei, &str);
1457 1458 1459
    VariantClear(v);
    if(FAILED(hres)) {
        IDispatch_Release(V_DISPATCH(obj));
1460
        return hres;
1461
    }
1462

1463
    hres = disp_get_id(ctx->script, V_DISPATCH(obj), str, 0, &id);
1464
    IDispatch_Release(V_DISPATCH(obj));
1465 1466
    SysFreeString(str);
    if(SUCCEEDED(hres))
1467
        ret = TRUE;
1468
    else if(hres == DISP_E_UNKNOWNNAME)
1469
        ret = FALSE;
1470 1471 1472
    else
        return hres;

1473
    return stack_push_bool(ctx, ret);
Jacek Caban's avatar
Jacek Caban committed
1474 1475
}

1476
/* ECMA-262 3rd Edition    11.6.1 */
1477
static HRESULT add_eval(script_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexcept_t *ei, VARIANT *retv)
Jacek Caban's avatar
Jacek Caban committed
1478
{
1479 1480 1481
    VARIANT r, l;
    HRESULT hres;

1482
    hres = to_primitive(ctx, lval, ei, &l, NO_HINT);
1483 1484 1485
    if(FAILED(hres))
        return hres;

1486
    hres = to_primitive(ctx, rval, ei, &r, NO_HINT);
1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497
    if(FAILED(hres)) {
        VariantClear(&l);
        return hres;
    }

    if(V_VT(&l) == VT_BSTR || V_VT(&r) == VT_BSTR) {
        BSTR lstr = NULL, rstr = NULL;

        if(V_VT(&l) == VT_BSTR)
            lstr = V_BSTR(&l);
        else
1498
            hres = to_string(ctx, &l, ei, &lstr);
1499 1500 1501 1502 1503

        if(SUCCEEDED(hres)) {
            if(V_VT(&r) == VT_BSTR)
                rstr = V_BSTR(&r);
            else
1504
                hres = to_string(ctx, &r, ei, &rstr);
1505 1506 1507 1508 1509 1510 1511 1512 1513 1514
        }

        if(SUCCEEDED(hres)) {
            int len1, len2;

            len1 = SysStringLen(lstr);
            len2 = SysStringLen(rstr);

            V_VT(retv) = VT_BSTR;
            V_BSTR(retv) = SysAllocStringLen(NULL, len1+len2);
1515 1516 1517 1518 1519
            if(len1)
                memcpy(V_BSTR(retv), lstr, len1*sizeof(WCHAR));
            if(len2)
                memcpy(V_BSTR(retv)+len1, rstr, len2*sizeof(WCHAR));
            V_BSTR(retv)[len1+len2] = 0;
1520 1521
        }

1522
        if(V_VT(&l) != VT_BSTR)
1523
            SysFreeString(lstr);
1524
        if(V_VT(&r) != VT_BSTR)
1525 1526
            SysFreeString(rstr);
    }else {
1527
        double nl, nr;
1528

1529
        hres = to_number(ctx, &l, ei, &nl);
1530
        if(SUCCEEDED(hres)) {
1531
            hres = to_number(ctx, &r, ei, &nr);
1532
            if(SUCCEEDED(hres))
1533
                num_set_val(retv, nl + nr);
1534 1535 1536 1537 1538 1539 1540 1541 1542
        }
    }

    VariantClear(&r);
    VariantClear(&l);
    return hres;
}

/* ECMA-262 3rd Edition    11.6.1 */
1543
static HRESULT interp_add(exec_ctx_t *ctx)
1544
{
1545 1546
    VARIANT *l, *r, ret;
    HRESULT hres;
1547

1548 1549 1550 1551 1552
    r = stack_pop(ctx);
    l = stack_pop(ctx);

    TRACE("%s + %s\n", debugstr_variant(l), debugstr_variant(r));

1553
    hres = add_eval(ctx->script, l, r, ctx->ei, &ret);
1554 1555
    VariantClear(l);
    VariantClear(r);
1556 1557
    if(FAILED(hres))
        return hres;
1558

1559
    return stack_push(ctx, &ret);
Jacek Caban's avatar
Jacek Caban committed
1560 1561
}

1562
/* ECMA-262 3rd Edition    11.6.2 */
1563
static HRESULT interp_sub(exec_ctx_t *ctx)
1564
{
1565
    double l, r;
1566
    HRESULT hres;
1567 1568 1569

    TRACE("\n");

1570 1571 1572 1573 1574 1575 1576 1577
    hres = stack_pop_number(ctx, &r);
    if(FAILED(hres))
        return hres;

    hres = stack_pop_number(ctx, &l);
    if(FAILED(hres))
        return hres;

1578
    return stack_push_number(ctx, l-r);
Jacek Caban's avatar
Jacek Caban committed
1579 1580
}

1581
/* ECMA-262 3rd Edition    11.5.1 */
1582
static HRESULT interp_mul(exec_ctx_t *ctx)
1583
{
1584
    double l, r;
1585
    HRESULT hres;
1586 1587 1588

    TRACE("\n");

1589 1590 1591 1592 1593 1594 1595 1596
    hres = stack_pop_number(ctx, &r);
    if(FAILED(hres))
        return hres;

    hres = stack_pop_number(ctx, &l);
    if(FAILED(hres))
        return hres;

1597
    return stack_push_number(ctx, l*r);
Jacek Caban's avatar
Jacek Caban committed
1598 1599
}

1600
/* ECMA-262 3rd Edition    11.5.2 */
1601
static HRESULT interp_div(exec_ctx_t *ctx)
1602
{
1603
    double l, r;
1604
    HRESULT hres;
1605 1606 1607

    TRACE("\n");

1608 1609 1610 1611 1612 1613 1614 1615
    hres = stack_pop_number(ctx, &r);
    if(FAILED(hres))
        return hres;

    hres = stack_pop_number(ctx, &l);
    if(FAILED(hres))
        return hres;

1616
    return stack_push_number(ctx, l/r);
Jacek Caban's avatar
Jacek Caban committed
1617 1618
}

1619
/* ECMA-262 3rd Edition    11.5.3 */
1620
static HRESULT interp_mod(exec_ctx_t *ctx)
1621
{
1622
    double l, r;
1623
    HRESULT hres;
1624 1625 1626

    TRACE("\n");

1627 1628 1629 1630 1631 1632 1633 1634
    hres = stack_pop_number(ctx, &r);
    if(FAILED(hres))
        return hres;

    hres = stack_pop_number(ctx, &l);
    if(FAILED(hres))
        return hres;

1635
    return stack_push_number(ctx, fmod(l, r));
Jacek Caban's avatar
Jacek Caban committed
1636 1637
}

1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652
/* ECMA-262 3rd Edition    11.4.2 */
static HRESULT interp_delete(exec_ctx_t *ctx)
{
    VARIANT *obj_var, *name_var;
    IDispatchEx *dispex;
    IDispatch *obj;
    BSTR name;
    BOOL ret;
    HRESULT hres;

    TRACE("\n");

    name_var = stack_pop(ctx);
    obj_var = stack_pop(ctx);

1653
    hres = to_object(ctx->script, obj_var, &obj);
1654 1655 1656 1657 1658 1659
    VariantClear(obj_var);
    if(FAILED(hres)) {
        VariantClear(name_var);
        return hres;
    }

1660
    hres = to_string(ctx->script, name_var, ctx->ei, &name);
1661 1662 1663 1664 1665 1666 1667 1668
    VariantClear(name_var);
    if(FAILED(hres)) {
        IDispatch_Release(obj);
        return hres;
    }

    hres = IDispatch_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
    if(SUCCEEDED(hres)) {
1669
        hres = IDispatchEx_DeleteMemberByName(dispex, name, make_grfdex(ctx->script, fdexNameCaseSensitive));
1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684
        ret = TRUE;
        IDispatchEx_Release(dispex);
    }else {
        hres = S_OK;
        ret = FALSE;
    }

    IDispatch_Release(obj);
    SysFreeString(name);
    if(FAILED(hres))
        return hres;

    return stack_push_bool(ctx, ret);
}

1685 1686 1687
/* ECMA-262 3rd Edition    11.4.2 */
static HRESULT interp_delete_ident(exec_ctx_t *ctx)
{
1688
    const BSTR arg = get_op_bstr(ctx, 0);
1689 1690 1691 1692 1693 1694 1695
    IDispatchEx *dispex;
    exprval_t exprval;
    BOOL ret = FALSE;
    HRESULT hres;

    TRACE("%s\n", debugstr_w(arg));

1696
    hres = identifier_eval(ctx->script, arg, &exprval);
1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719
    if(FAILED(hres))
        return hres;

    if(exprval.type != EXPRVAL_IDREF) {
        FIXME("Unsupported exprval\n");
        exprval_release(&exprval);
        return E_NOTIMPL;
    }

    hres = IDispatch_QueryInterface(exprval.u.idref.disp, &IID_IDispatchEx, (void**)&dispex);
    IDispatch_Release(exprval.u.idref.disp);
    if(SUCCEEDED(hres)) {
        hres = IDispatchEx_DeleteMemberByDispID(dispex, exprval.u.idref.id);
        IDispatchEx_Release(dispex);
        if(FAILED(hres))
            return hres;

        ret = TRUE;
    }

    return stack_push_bool(ctx, ret);
}

1720
/* ECMA-262 3rd Edition    11.4.2 */
1721
static HRESULT interp_void(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
1722
{
1723
    VARIANT v;
1724 1725 1726

    TRACE("\n");

1727
    stack_popn(ctx, 1);
1728

1729 1730
    V_VT(&v) = VT_EMPTY;
    return stack_push(ctx, &v);
Jacek Caban's avatar
Jacek Caban committed
1731 1732
}

1733
/* ECMA-262 3rd Edition    11.4.3 */
1734
static HRESULT typeof_string(VARIANT *v, const WCHAR **ret)
Jacek Caban's avatar
Jacek Caban committed
1735
{
1736
    switch(V_VT(v)) {
1737
    case VT_EMPTY:
1738
        *ret = undefinedW;
1739 1740
        break;
    case VT_NULL:
1741
        *ret = objectW;
1742 1743
        break;
    case VT_BOOL:
1744
        *ret = booleanW;
1745 1746 1747
        break;
    case VT_I4:
    case VT_R8:
1748
        *ret = numberW;
1749 1750
        break;
    case VT_BSTR:
1751
        *ret = stringW;
1752 1753
        break;
    case VT_DISPATCH: {
1754
        jsdisp_t *dispex;
1755

1756
        if(V_DISPATCH(v) && (dispex = iface_to_jsdisp((IUnknown*)V_DISPATCH(v)))) {
1757 1758
            *ret = is_class(dispex, JSCLASS_FUNCTION) ? functionW : objectW;
            jsdisp_release(dispex);
1759
        }else {
1760
            *ret = objectW;
1761 1762 1763 1764
        }
        break;
    }
    default:
1765 1766
        FIXME("unhandled vt %d\n", V_VT(v));
        return E_NOTIMPL;
1767 1768
    }

1769
    return S_OK;
1770 1771
}

1772 1773
/* ECMA-262 3rd Edition    11.4.3 */
static HRESULT interp_typeofid(exec_ctx_t *ctx)
1774
{
1775 1776 1777 1778
    const WCHAR *ret;
    IDispatch *obj;
    VARIANT v;
    DISPID id;
1779 1780
    HRESULT hres;

1781 1782
    static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};

1783 1784
    TRACE("\n");

1785 1786 1787 1788 1789
    obj = stack_pop_objid(ctx, &id);
    if(!obj)
        return stack_push_string(ctx, undefinedW);

    V_VT(&v) = VT_EMPTY;
1790
    hres = disp_propget(ctx->script, obj, id, &v, ctx->ei);
1791 1792 1793 1794 1795 1796
    IDispatch_Release(obj);
    if(FAILED(hres))
        return stack_push_string(ctx, unknownW);

    hres = typeof_string(&v, &ret);
    VariantClear(&v);
1797 1798 1799
    if(FAILED(hres))
        return hres;

1800 1801 1802 1803 1804 1805
    return stack_push_string(ctx, ret);
}

/* ECMA-262 3rd Edition    11.4.3 */
static HRESULT interp_typeofident(exec_ctx_t *ctx)
{
1806
    const BSTR arg = get_op_bstr(ctx, 0);
1807 1808 1809 1810 1811 1812 1813
    exprval_t exprval;
    const WCHAR *ret;
    VARIANT v;
    HRESULT hres;

    TRACE("%s\n", debugstr_w(arg));

1814
    hres = identifier_eval(ctx->script, arg, &exprval);
1815 1816 1817 1818 1819 1820 1821 1822 1823
    if(FAILED(hres))
        return hres;

    if(exprval.type == EXPRVAL_INVALID) {
        hres = stack_push_string(ctx, undefinedW);
        exprval_release(&exprval);
        return hres;
    }

1824
    hres = exprval_to_value(ctx->script, &exprval, ctx->ei, &v);
1825 1826 1827
    exprval_release(&exprval);
    if(FAILED(hres))
        return hres;
1828

1829 1830 1831 1832
    hres = typeof_string(&v, &ret);
    VariantClear(&v);
    if(FAILED(hres))
        return hres;
1833

1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852
    return stack_push_string(ctx, ret);
}

/* ECMA-262 3rd Edition    11.4.3 */
static HRESULT interp_typeof(exec_ctx_t *ctx)
{
    const WCHAR *ret;
    VARIANT *v;
    HRESULT hres;

    TRACE("\n");

    v = stack_pop(ctx);
    hres = typeof_string(v, &ret);
    VariantClear(v);
    if(FAILED(hres))
        return hres;

    return stack_push_string(ctx, ret);
Jacek Caban's avatar
Jacek Caban committed
1853 1854
}

1855
/* ECMA-262 3rd Edition    11.4.7 */
1856
static HRESULT interp_minus(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
1857
{
1858
    double n;
1859 1860 1861 1862
    HRESULT hres;

    TRACE("\n");

1863
    hres = stack_pop_number(ctx, &n);
1864 1865 1866
    if(FAILED(hres))
        return hres;

1867
    return stack_push_number(ctx, -n);
Jacek Caban's avatar
Jacek Caban committed
1868 1869
}

1870
/* ECMA-262 3rd Edition    11.4.6 */
1871
static HRESULT interp_tonum(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
1872
{
1873 1874
    VARIANT *v;
    double n;
1875 1876 1877 1878
    HRESULT hres;

    TRACE("\n");

1879
    v = stack_pop(ctx);
1880
    hres = to_number(ctx->script, v, ctx->ei, &n);
1881
    VariantClear(v);
1882 1883 1884
    if(FAILED(hres))
        return hres;

1885
    return stack_push_number(ctx, n);
Jacek Caban's avatar
Jacek Caban committed
1886 1887
}

1888
/* ECMA-262 3rd Edition    11.3.1 */
1889
static HRESULT interp_postinc(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
1890
{
1891
    const int arg = get_op_int(ctx, 0);
1892 1893 1894
    IDispatch *obj;
    DISPID id;
    VARIANT v;
1895 1896
    HRESULT hres;

1897
    TRACE("%d\n", arg);
1898

1899 1900
    obj = stack_pop_objid(ctx, &id);
    if(!obj)
1901
        return throw_type_error(ctx->script, ctx->ei, JS_E_OBJECT_EXPECTED, NULL);
1902

1903
    hres = disp_propget(ctx->script, obj, id, &v, ctx->ei);
1904
    if(SUCCEEDED(hres)) {
1905 1906
        VARIANT inc;
        double n;
1907

1908
        hres = to_number(ctx->script, &v, ctx->ei, &n);
1909
        if(SUCCEEDED(hres)) {
1910
            num_set_val(&inc, n+(double)arg);
1911
            hres = disp_propput(ctx->script, obj, id, &inc, ctx->ei);
1912
        }
1913 1914
        if(FAILED(hres))
            VariantClear(&v);
1915
    }
1916
    IDispatch_Release(obj);
1917 1918 1919
    if(FAILED(hres))
        return hres;

1920
    return stack_push(ctx, &v);
Jacek Caban's avatar
Jacek Caban committed
1921 1922
}

1923
/* ECMA-262 3rd Edition    11.4.4, 11.4.5 */
1924
static HRESULT interp_preinc(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
1925
{
1926
    const int arg = get_op_int(ctx, 0);
1927 1928 1929
    IDispatch *obj;
    DISPID id;
    VARIANT v;
1930 1931
    HRESULT hres;

1932
    TRACE("%d\n", arg);
1933

1934 1935
    obj = stack_pop_objid(ctx, &id);
    if(!obj)
1936
        return throw_type_error(ctx->script, ctx->ei, JS_E_OBJECT_EXPECTED, NULL);
1937

1938
    hres = disp_propget(ctx->script, obj, id, &v, ctx->ei);
1939
    if(SUCCEEDED(hres)) {
1940
        double n;
1941

1942
        hres = to_number(ctx->script, &v, ctx->ei, &n);
1943 1944
        VariantClear(&v);
        if(SUCCEEDED(hres)) {
1945
            num_set_val(&v, n+(double)arg);
1946
            hres = disp_propput(ctx->script, obj, id, &v, ctx->ei);
1947
        }
1948
    }
1949
    IDispatch_Release(obj);
1950 1951 1952
    if(FAILED(hres))
        return hres;

1953
    return stack_push(ctx, &v);
Jacek Caban's avatar
Jacek Caban committed
1954 1955
}

1956
/* ECMA-262 3rd Edition    11.9.3 */
1957
static HRESULT equal_values(script_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexcept_t *ei, BOOL *ret)
Jacek Caban's avatar
Jacek Caban committed
1958
{
1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982
    if(V_VT(lval) == V_VT(rval) || (is_num_vt(V_VT(lval)) && is_num_vt(V_VT(rval))))
       return equal2_values(lval, rval, ret);

    /* FIXME: NULL disps should be handled in more general way */
    if(V_VT(lval) == VT_DISPATCH && !V_DISPATCH(lval)) {
        VARIANT v;
        V_VT(&v) = VT_NULL;
        return equal_values(ctx, &v, rval, ei, ret);
    }

    if(V_VT(rval) == VT_DISPATCH && !V_DISPATCH(rval)) {
        VARIANT v;
        V_VT(&v) = VT_NULL;
        return equal_values(ctx, lval, &v, ei, ret);
    }

    if((V_VT(lval) == VT_NULL && V_VT(rval) == VT_EMPTY) ||
       (V_VT(lval) == VT_EMPTY && V_VT(rval) == VT_NULL)) {
        *ret = TRUE;
        return S_OK;
    }

    if(V_VT(lval) == VT_BSTR && is_num_vt(V_VT(rval))) {
        VARIANT v;
1983
        double n;
1984 1985
        HRESULT hres;

1986
        hres = to_number(ctx, lval, ei, &n);
1987 1988 1989
        if(FAILED(hres))
            return hres;

1990 1991 1992
        /* FIXME: optimize */
        num_set_val(&v, n);

1993 1994 1995 1996 1997
        return equal_values(ctx, &v, rval, ei, ret);
    }

    if(V_VT(rval) == VT_BSTR && is_num_vt(V_VT(lval))) {
        VARIANT v;
1998
        double n;
1999 2000
        HRESULT hres;

2001
        hres = to_number(ctx, rval, ei, &n);
2002 2003 2004
        if(FAILED(hres))
            return hres;

2005 2006 2007
        /* FIXME: optimize */
        num_set_val(&v, n);

2008 2009 2010 2011 2012 2013
        return equal_values(ctx, lval, &v, ei, ret);
    }

    if(V_VT(rval) == VT_BOOL) {
        VARIANT v;

2014
        num_set_int(&v, V_BOOL(rval) ? 1 : 0);
2015 2016 2017 2018 2019 2020
        return equal_values(ctx, lval, &v, ei, ret);
    }

    if(V_VT(lval) == VT_BOOL) {
        VARIANT v;

2021
        num_set_int(&v, V_BOOL(lval) ? 1 : 0);
2022 2023 2024 2025 2026 2027 2028 2029
        return equal_values(ctx, &v, rval, ei, ret);
    }


    if(V_VT(rval) == VT_DISPATCH && (V_VT(lval) == VT_BSTR || is_num_vt(V_VT(lval)))) {
        VARIANT v;
        HRESULT hres;

2030
        hres = to_primitive(ctx, rval, ei, &v, NO_HINT);
2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044
        if(FAILED(hres))
            return hres;

        hres = equal_values(ctx, lval, &v, ei, ret);

        VariantClear(&v);
        return hres;
    }


    if(V_VT(lval) == VT_DISPATCH && (V_VT(rval) == VT_BSTR || is_num_vt(V_VT(rval)))) {
        VARIANT v;
        HRESULT hres;

2045
        hres = to_primitive(ctx, lval, ei, &v, NO_HINT);
2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060
        if(FAILED(hres))
            return hres;

        hres = equal_values(ctx, &v, rval, ei, ret);

        VariantClear(&v);
        return hres;
    }


    *ret = FALSE;
    return S_OK;
}

/* ECMA-262 3rd Edition    11.9.1 */
2061
static HRESULT interp_eq(exec_ctx_t *ctx)
2062
{
2063
    VARIANT *l, *r;
2064 2065 2066
    BOOL b;
    HRESULT hres;

2067 2068
    r = stack_pop(ctx);
    l = stack_pop(ctx);
2069

2070
    TRACE("%s == %s\n", debugstr_variant(l), debugstr_variant(r));
2071

2072
    hres = equal_values(ctx->script, l, r, ctx->ei, &b);
2073 2074
    VariantClear(l);
    VariantClear(r);
2075 2076 2077
    if(FAILED(hres))
        return hres;

2078
    return stack_push_bool(ctx, b);
Jacek Caban's avatar
Jacek Caban committed
2079 2080
}

2081
/* ECMA-262 3rd Edition    11.9.2 */
2082
static HRESULT interp_neq(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
2083
{
2084
    VARIANT *l, *r;
2085 2086 2087
    BOOL b;
    HRESULT hres;

2088 2089
    r = stack_pop(ctx);
    l = stack_pop(ctx);
2090

2091 2092
    TRACE("%s != %s\n", debugstr_variant(l), debugstr_variant(r));

2093
    hres = equal_values(ctx->script, l, r, ctx->ei, &b);
2094 2095
    VariantClear(l);
    VariantClear(r);
2096 2097 2098
    if(FAILED(hres))
        return hres;

2099
    return stack_push_bool(ctx, !b);
Jacek Caban's avatar
Jacek Caban committed
2100 2101
}

2102 2103
/* ECMA-262 3rd Edition    11.9.4 */
static HRESULT interp_eq2(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
2104
{
2105
    VARIANT *l, *r;
2106 2107
    BOOL b;
    HRESULT hres;
Jacek Caban's avatar
Jacek Caban committed
2108

2109 2110
    TRACE("\n");

2111 2112
    r = stack_pop(ctx);
    l = stack_pop(ctx);
2113

2114 2115 2116
    hres = equal2_values(r, l, &b);
    VariantClear(l);
    VariantClear(r);
2117 2118 2119
    if(FAILED(hres))
        return hres;

2120
    return stack_push_bool(ctx, b);
Jacek Caban's avatar
Jacek Caban committed
2121 2122
}

2123
/* ECMA-262 3rd Edition    11.9.5 */
2124
static HRESULT interp_neq2(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
2125
{
2126
    VARIANT *l, *r;
2127 2128 2129 2130 2131
    BOOL b;
    HRESULT hres;

    TRACE("\n");

2132 2133
    r = stack_pop(ctx);
    l = stack_pop(ctx);
2134

2135 2136 2137
    hres = equal2_values(r, l, &b);
    VariantClear(l);
    VariantClear(r);
2138 2139 2140
    if(FAILED(hres))
        return hres;

2141
    return stack_push_bool(ctx, !b);
Jacek Caban's avatar
Jacek Caban committed
2142 2143
}

2144
/* ECMA-262 3rd Edition    11.8.5 */
2145
static HRESULT less_eval(script_ctx_t *ctx, VARIANT *lval, VARIANT *rval, BOOL greater, jsexcept_t *ei, BOOL *ret)
Jacek Caban's avatar
Jacek Caban committed
2146
{
2147 2148
    double ln, rn;
    VARIANT l, r;
2149 2150
    HRESULT hres;

2151
    hres = to_primitive(ctx, lval, ei, &l, NO_HINT);
2152 2153 2154
    if(FAILED(hres))
        return hres;

2155
    hres = to_primitive(ctx, rval, ei, &r, NO_HINT);
2156 2157 2158 2159 2160 2161
    if(FAILED(hres)) {
        VariantClear(&l);
        return hres;
    }

    if(V_VT(&l) == VT_BSTR && V_VT(&r) == VT_BSTR) {
2162
        *ret = (strcmpW(V_BSTR(&l), V_BSTR(&r)) < 0) ^ greater;
2163 2164 2165 2166 2167
        SysFreeString(V_BSTR(&l));
        SysFreeString(V_BSTR(&r));
        return S_OK;
    }

2168
    hres = to_number(ctx, &l, ei, &ln);
2169 2170
    VariantClear(&l);
    if(SUCCEEDED(hres))
2171
        hres = to_number(ctx, &r, ei, &rn);
2172 2173 2174 2175
    VariantClear(&r);
    if(FAILED(hres))
        return hres;

2176
    *ret = !isnan(ln) && !isnan(rn) && ((ln < rn) ^ greater);
2177 2178 2179 2180
    return S_OK;
}

/* ECMA-262 3rd Edition    11.8.1 */
2181
static HRESULT interp_lt(exec_ctx_t *ctx)
2182
{
2183
    VARIANT *l, *r;
2184 2185 2186
    BOOL b;
    HRESULT hres;

2187 2188
    r = stack_pop(ctx);
    l = stack_pop(ctx);
2189

2190
    TRACE("%s < %s\n", debugstr_variant(l), debugstr_variant(r));
2191

2192
    hres = less_eval(ctx->script, l, r, FALSE, ctx->ei, &b);
2193 2194
    VariantClear(l);
    VariantClear(r);
2195 2196 2197
    if(FAILED(hres))
        return hres;

2198
    return stack_push_bool(ctx, b);
Jacek Caban's avatar
Jacek Caban committed
2199 2200
}

2201 2202
/* ECMA-262 3rd Edition    11.8.1 */
static HRESULT interp_lteq(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
2203
{
2204
    VARIANT *l, *r;
2205 2206 2207
    BOOL b;
    HRESULT hres;

2208 2209
    r = stack_pop(ctx);
    l = stack_pop(ctx);
2210

2211
    TRACE("%s <= %s\n", debugstr_variant(l), debugstr_variant(r));
2212

2213
    hres = less_eval(ctx->script, r, l, TRUE, ctx->ei, &b);
2214 2215
    VariantClear(l);
    VariantClear(r);
2216 2217 2218
    if(FAILED(hres))
        return hres;

2219
    return stack_push_bool(ctx, b);
Jacek Caban's avatar
Jacek Caban committed
2220 2221
}

2222
/* ECMA-262 3rd Edition    11.8.2 */
2223
static HRESULT interp_gt(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
2224
{
2225
    VARIANT *l, *r;
2226 2227 2228
    BOOL b;
    HRESULT hres;

2229 2230
    r = stack_pop(ctx);
    l = stack_pop(ctx);
2231

2232
    TRACE("%s > %s\n", debugstr_variant(l), debugstr_variant(r));
2233

2234
    hres = less_eval(ctx->script, r, l, FALSE, ctx->ei, &b);
2235 2236
    VariantClear(l);
    VariantClear(r);
2237 2238 2239
    if(FAILED(hres))
        return hres;

2240
    return stack_push_bool(ctx, b);
Jacek Caban's avatar
Jacek Caban committed
2241 2242
}

2243
/* ECMA-262 3rd Edition    11.8.4 */
2244
static HRESULT interp_gteq(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
2245
{
2246
    VARIANT *l, *r;
2247 2248 2249
    BOOL b;
    HRESULT hres;

2250 2251
    r = stack_pop(ctx);
    l = stack_pop(ctx);
2252

2253
    TRACE("%s >= %s\n", debugstr_variant(l), debugstr_variant(r));
2254

2255
    hres = less_eval(ctx->script, l, r, TRUE, ctx->ei, &b);
2256 2257
    VariantClear(l);
    VariantClear(r);
2258 2259 2260
    if(FAILED(hres))
        return hres;

2261
    return stack_push_bool(ctx, b);
Jacek Caban's avatar
Jacek Caban committed
2262 2263
}

2264
/* ECMA-262 3rd Edition    11.4.8 */
2265
static HRESULT interp_bneg(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
2266
{
2267
    VARIANT *v;
2268 2269 2270 2271 2272
    INT i;
    HRESULT hres;

    TRACE("\n");

2273
    v = stack_pop(ctx);
2274
    hres = to_int32(ctx->script, v, ctx->ei, &i);
2275
    VariantClear(v);
2276 2277 2278
    if(FAILED(hres))
        return hres;

2279
    return stack_push_int(ctx, ~i);
Jacek Caban's avatar
Jacek Caban committed
2280 2281
}

2282
/* ECMA-262 3rd Edition    11.4.9 */
2283
static HRESULT interp_neg(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
2284
{
2285
    VARIANT *v;
2286 2287 2288 2289 2290
    VARIANT_BOOL b;
    HRESULT hres;

    TRACE("\n");

2291 2292 2293
    v = stack_pop(ctx);
    hres = to_boolean(v, &b);
    VariantClear(v);
2294 2295 2296
    if(FAILED(hres))
        return hres;

2297
    return stack_push_bool(ctx, !b);
Jacek Caban's avatar
Jacek Caban committed
2298 2299
}

2300
/* ECMA-262 3rd Edition    11.7.1 */
2301
static HRESULT interp_lshift(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
2302
{
2303 2304 2305
    DWORD r;
    INT l;
    HRESULT hres;
2306

2307 2308 2309 2310 2311 2312 2313
    hres = stack_pop_uint(ctx, &r);
    if(FAILED(hres))
        return hres;

    hres = stack_pop_int(ctx, &l);
    if(FAILED(hres))
        return hres;
2314

2315
    return stack_push_int(ctx, l << (r&0x1f));
Jacek Caban's avatar
Jacek Caban committed
2316 2317
}

2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335
/* ECMA-262 3rd Edition    11.7.2 */
static HRESULT interp_rshift(exec_ctx_t *ctx)
{
    DWORD r;
    INT l;
    HRESULT hres;

    hres = stack_pop_uint(ctx, &r);
    if(FAILED(hres))
        return hres;

    hres = stack_pop_int(ctx, &l);
    if(FAILED(hres))
        return hres;

    return stack_push_int(ctx, l >> (r&0x1f));
}

2336
/* ECMA-262 3rd Edition    11.7.3 */
2337
static HRESULT interp_rshift2(exec_ctx_t *ctx)
Jacek Caban's avatar
Jacek Caban committed
2338
{
2339 2340
    DWORD r, l;
    HRESULT hres;
2341

2342 2343 2344
    hres = stack_pop_uint(ctx, &r);
    if(FAILED(hres))
        return hres;
2345

2346 2347 2348 2349 2350
    hres = stack_pop_uint(ctx, &l);
    if(FAILED(hres))
        return hres;

    return stack_push_int(ctx, l >> (r&0x1f));
Jacek Caban's avatar
Jacek Caban committed
2351 2352
}

2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366
/* ECMA-262 3rd Edition    11.13.1 */
static HRESULT interp_assign(exec_ctx_t *ctx)
{
    IDispatch *disp;
    DISPID id;
    VARIANT *v;
    HRESULT hres;

    TRACE("\n");

    v = stack_pop(ctx);
    disp = stack_pop_objid(ctx, &id);

    if(!disp)
2367
        return throw_reference_error(ctx->script, ctx->ei, JS_E_ILLEGAL_ASSIGN, NULL);
2368

2369
    hres = disp_propput(ctx->script, disp, id, v, ctx->ei);
2370 2371 2372 2373 2374 2375 2376 2377 2378
    IDispatch_Release(disp);
    if(FAILED(hres)) {
        VariantClear(v);
        return hres;
    }

    return stack_push(ctx, v);
}

2379 2380 2381
/* JScript extension */
static HRESULT interp_assign_call(exec_ctx_t *ctx)
{
2382
    const unsigned arg = get_op_uint(ctx, 0);
2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393
    IDispatch *disp;
    VARIANT *v;
    DISPID id;
    HRESULT hres;

    TRACE("%u\n", arg);

    disp = stack_topn_objid(ctx, arg+1, &id);
    if(!disp)
        return throw_reference_error(ctx->script, ctx->ei, JS_E_ILLEGAL_ASSIGN, NULL);

2394
    hres = disp_call(ctx->script, disp, id, DISPATCH_PROPERTYPUT, arg+1, stack_args(ctx,arg+1), NULL, ctx->ei);
2395 2396 2397 2398 2399 2400 2401 2402
    if(FAILED(hres))
        return hres;

    v = stack_pop(ctx);
    stack_popn(ctx, arg+2);
    return stack_push(ctx, v);
}

2403 2404 2405 2406 2407 2408 2409 2410 2411 2412
static HRESULT interp_undefined(exec_ctx_t *ctx)
{
    VARIANT v;

    TRACE("\n");

    V_VT(&v) = VT_EMPTY;
    return stack_push(ctx, &v);
}

2413
static HRESULT interp_jmp(exec_ctx_t *ctx)
2414
{
2415
    const unsigned arg = get_op_uint(ctx, 0);
2416

2417
    TRACE("%u\n", arg);
2418 2419 2420 2421 2422

    ctx->ip = arg;
    return S_OK;
}

2423 2424
static HRESULT interp_jmp_z(exec_ctx_t *ctx)
{
2425
    const unsigned arg = get_op_uint(ctx, 0);
2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444
    VARIANT_BOOL b;
    VARIANT *v;
    HRESULT hres;

    TRACE("\n");

    v = stack_pop(ctx);
    hres = to_boolean(v, &b);
    VariantClear(v);
    if(FAILED(hres))
        return hres;

    if(b)
        ctx->ip++;
    else
        ctx->ip = arg;
    return S_OK;
}

2445 2446 2447 2448 2449 2450 2451 2452
static HRESULT interp_pop(exec_ctx_t *ctx)
{
    TRACE("\n");

    stack_popn(ctx, 1);
    return S_OK;
}

2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463
static HRESULT interp_ret(exec_ctx_t *ctx)
{
    TRACE("\n");

    ctx->ip = -1;
    return S_OK;
}

typedef HRESULT (*op_func_t)(exec_ctx_t*);

static const op_func_t op_funcs[] = {
2464
#define X(x,a,b,c) interp_##x,
2465 2466 2467 2468 2469
OP_LIST
#undef X
};

static const unsigned op_move[] = {
2470
#define X(a,x,b,c) x,
2471 2472 2473 2474
OP_LIST
#undef X
};

2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492
static HRESULT unwind_exception(exec_ctx_t *ctx)
{
    except_frame_t *except_frame;
    VARIANT except_val;
    BSTR ident;
    HRESULT hres;

    except_frame = ctx->except_frame;
    ctx->except_frame = except_frame->next;

    assert(except_frame->stack_top <= ctx->top);
    stack_popn(ctx, ctx->top - except_frame->stack_top);

    while(except_frame->scope != ctx->scope_chain)
        scope_pop(&ctx->scope_chain);

    ctx->ip = except_frame->catch_off;

2493 2494
    except_val = ctx->ei->var;
    memset(ctx->ei, 0, sizeof(*ctx->ei));
2495 2496 2497 2498 2499 2500 2501

    ident = except_frame->ident;
    heap_free(except_frame);

    if(ident) {
        jsdisp_t *scope_obj;

2502
        hres = create_dispex(ctx->script, NULL, NULL, &scope_obj);
2503
        if(SUCCEEDED(hres)) {
2504
            hres = jsdisp_propput_name(scope_obj, ident, &except_val, ctx->ei);
2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531
            if(FAILED(hres))
                jsdisp_release(scope_obj);
        }
        VariantClear(&except_val);
        if(FAILED(hres))
            return hres;

        hres = scope_push(ctx->scope_chain, scope_obj, &ctx->scope_chain);
        jsdisp_release(scope_obj);
    }else {
        VARIANT v;

        hres = stack_push(ctx, &except_val);
        if(FAILED(hres))
            return hres;

        hres = stack_push_bool(ctx, FALSE);
        if(FAILED(hres))
            return hres;

        V_VT(&v) = VT_EMPTY;
        hres = stack_push(ctx, &v);
    }

    return hres;
}

2532
static HRESULT enter_bytecode(script_ctx_t *ctx, bytecode_t *code, function_code_t *func, jsexcept_t *ei, VARIANT *ret)
2533 2534
{
    exec_ctx_t *exec_ctx = ctx->exec_ctx;
2535
    except_frame_t *prev_except_frame;
2536
    function_code_t *prev_func;
2537
    unsigned prev_ip, prev_top;
2538
    scope_chain_t *prev_scope;
2539
    bytecode_t *prev_code;
2540
    jsexcept_t *prev_ei;
2541 2542 2543 2544 2545 2546
    jsop_t op;
    HRESULT hres = S_OK;

    TRACE("\n");

    prev_top = exec_ctx->top;
2547
    prev_scope = exec_ctx->scope_chain;
2548
    prev_except_frame = exec_ctx->except_frame;
2549
    prev_ip = exec_ctx->ip;
2550
    prev_ei = exec_ctx->ei;
2551
    prev_code = exec_ctx->code;
2552 2553
    prev_func = exec_ctx->func_code;
    exec_ctx->ip = func->instr_off;
2554
    exec_ctx->ei = ei;
2555
    exec_ctx->except_frame = NULL;
2556
    exec_ctx->code = code;
2557
    exec_ctx->func_code = func;
2558

2559
    while(exec_ctx->ip != -1) {
2560
        op = code->instrs[exec_ctx->ip].op;
2561
        hres = op_funcs[op](exec_ctx);
2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573
        if(FAILED(hres)) {
            TRACE("EXCEPTION\n");

            if(!exec_ctx->except_frame)
                break;

            hres = unwind_exception(exec_ctx);
            if(FAILED(hres))
                break;
        }else {
            exec_ctx->ip += op_move[op];
        }
2574 2575 2576
    }

    exec_ctx->ip = prev_ip;
2577
    exec_ctx->ei = prev_ei;
2578
    exec_ctx->except_frame = prev_except_frame;
2579
    exec_ctx->code = prev_code;
2580
    exec_ctx->func_code = prev_func;
2581

2582
    if(FAILED(hres)) {
2583 2584
        while(exec_ctx->scope_chain != prev_scope)
            scope_pop(&exec_ctx->scope_chain);
2585
        stack_popn(exec_ctx, exec_ctx->top-prev_top);
2586 2587 2588 2589
        return hres;
    }

    assert(exec_ctx->top == prev_top+1 || exec_ctx->top == prev_top);
2590
    assert(exec_ctx->scope_chain == prev_scope);
2591 2592 2593 2594 2595 2596 2597 2598

    if(exec_ctx->top == prev_top)
        V_VT(ret) = VT_EMPTY;
    else
        *ret = *stack_pop(exec_ctx);
    return S_OK;
}

2599
HRESULT exec_source(exec_ctx_t *ctx, bytecode_t *code, function_code_t *func, BOOL from_eval,
2600 2601
        jsexcept_t *ei, VARIANT *retv)
{
2602
    exec_ctx_t *prev_ctx;
2603
    VARIANT val;
2604
    unsigned i;
2605 2606
    HRESULT hres = S_OK;

2607
    for(i = 0; i < func->func_cnt; i++) {
2608 2609 2610
        jsdisp_t *func_obj;
        VARIANT var;

2611
        if(!func->funcs[i].name)
2612 2613
            continue;

2614
        hres = create_source_function(ctx->script, code, func->funcs+i, ctx->scope_chain, &func_obj);
2615 2616 2617 2618
        if(FAILED(hres))
            return hres;

        var_set_jsdisp(&var, func_obj);
2619
        hres = jsdisp_propput_name(ctx->var_disp, func->funcs[i].name, &var, ei);
2620 2621 2622 2623 2624
        jsdisp_release(func_obj);
        if(FAILED(hres))
            return hres;
    }

2625 2626 2627
    for(i=0; i < func->var_cnt; i++) {
        if(!ctx->is_global || !lookup_global_members(ctx->script, func->variables[i], NULL)) {
            DISPID id = 0;
2628

2629 2630 2631 2632
            hres = jsdisp_get_id(ctx->var_disp, func->variables[i], fdexNameEnsure, &id);
            if(FAILED(hres))
                return hres;
        }
2633 2634
    }

2635 2636
    prev_ctx = ctx->script->exec_ctx;
    ctx->script->exec_ctx = ctx;
2637

2638
    hres = enter_bytecode(ctx->script, code, func, ei, &val);
2639 2640
    assert(ctx->script->exec_ctx == ctx);
    ctx->script->exec_ctx = prev_ctx;
2641
    if(FAILED(hres))
2642 2643 2644 2645
        return hres;

    if(retv)
        *retv = val;
2646 2647
    else
        VariantClear(&val);
2648 2649
    return S_OK;
}