[JSCRIPT] Sync with Wine Staging 1.9.16. CORE-11866
authorAmine Khaldi <amine.khaldi@reactos.org>
Fri, 19 Aug 2016 09:36:35 +0000 (09:36 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Fri, 19 Aug 2016 09:36:35 +0000 (09:36 +0000)
svn path=/trunk/; revision=72346

16 files changed:
reactos/dll/win32/jscript/array.c
reactos/dll/win32/jscript/compile.c
reactos/dll/win32/jscript/dispex.c
reactos/dll/win32/jscript/engine.c
reactos/dll/win32/jscript/engine.h
reactos/dll/win32/jscript/function.c
reactos/dll/win32/jscript/global.c
reactos/dll/win32/jscript/jscript.c
reactos/dll/win32/jscript/jscript.h
reactos/dll/win32/jscript/json.c
reactos/dll/win32/jscript/jsregexp.c
reactos/dll/win32/jscript/jsutils.c
reactos/dll/win32/jscript/object.c
reactos/dll/win32/jscript/parser.h
reactos/dll/win32/jscript/string.c
reactos/media/doc/README.WINE

index 315d5d4..e0c02e1 100644 (file)
@@ -178,7 +178,7 @@ static HRESULT concat_obj(jsdisp_t *array, IDispatch *obj, DWORD *len)
     jsdisp_t *jsobj;
     HRESULT hres;
 
     jsdisp_t *jsobj;
     HRESULT hres;
 
-    jsobj = iface_to_jsdisp((IUnknown*)obj);
+    jsobj = iface_to_jsdisp(obj);
     if(jsobj) {
         if(is_class(jsobj, JSCLASS_ARRAY)) {
             hres = concat_array(array, (ArrayInstance*)jsobj, len);
     if(jsobj) {
         if(is_class(jsobj, JSCLASS_ARRAY)) {
             hres = concat_array(array, (ArrayInstance*)jsobj, len);
@@ -688,7 +688,7 @@ static HRESULT Array_sort(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigne
             return E_FAIL;
         }
 
             return E_FAIL;
         }
 
-        cmp_func = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
+        cmp_func = iface_to_jsdisp(get_object(argv[0]));
         if(!cmp_func || !is_class(cmp_func, JSCLASS_FUNCTION)) {
             WARN("cmp_func is not a function\n");
             if(cmp_func)
         if(!cmp_func || !is_class(cmp_func, JSCLASS_FUNCTION)) {
             WARN("cmp_func is not a function\n");
             if(cmp_func)
index 39ba79a..c7e040e 100644 (file)
@@ -46,12 +46,13 @@ typedef struct {
     unsigned labels_size;
     unsigned labels_cnt;
 
     unsigned labels_size;
     unsigned labels_cnt;
 
+    local_ref_t *locals_buf;
+    unsigned locals_buf_size;
+    unsigned locals_cnt;
+
     statement_ctx_t *stat_ctx;
     function_code_t *func;
 
     statement_ctx_t *stat_ctx;
     function_code_t *func;
 
-    variable_declaration_t *var_head;
-    variable_declaration_t *var_tail;
-
     function_expression_t *func_head;
     function_expression_t *func_tail;
 } compiler_ctx_t;
     function_expression_t *func_head;
     function_expression_t *func_tail;
 } compiler_ctx_t;
@@ -399,6 +400,40 @@ static inline BOOL is_memberid_expr(expression_type_t type)
     return type == EXPR_IDENT || type == EXPR_MEMBER || type == EXPR_ARRAY;
 }
 
     return type == EXPR_IDENT || type == EXPR_MEMBER || type == EXPR_ARRAY;
 }
 
+static BOOL bind_local(compiler_ctx_t *ctx, const WCHAR *identifier, int *ret_ref)
+{
+    statement_ctx_t *iter;
+    local_ref_t *ref;
+
+    for(iter = ctx->stat_ctx; iter; iter = iter->next) {
+        if(iter->using_scope)
+            return FALSE;
+    }
+
+    ref = lookup_local(ctx->func, identifier);
+    if(!ref)
+        return FALSE;
+
+    *ret_ref = ref->ref;
+    return TRUE;
+}
+
+static HRESULT emit_identifier_ref(compiler_ctx_t *ctx, const WCHAR *identifier, unsigned flags)
+{
+    int local_ref;
+    if(bind_local(ctx, identifier, &local_ref))
+        return push_instr_int(ctx, OP_local_ref, local_ref);
+    return push_instr_bstr_uint(ctx, OP_identid, identifier, flags);
+}
+
+static HRESULT emit_identifier(compiler_ctx_t *ctx, const WCHAR *identifier)
+{
+    int local_ref;
+    if(bind_local(ctx, identifier, &local_ref))
+        return push_instr_int(ctx, OP_local, local_ref);
+    return push_instr_bstr(ctx, OP_ident, identifier);
+}
+
 static HRESULT compile_memberid_expression(compiler_ctx_t *ctx, expression_t *expr, unsigned flags)
 {
     HRESULT hres = S_OK;
 static HRESULT compile_memberid_expression(compiler_ctx_t *ctx, expression_t *expr, unsigned flags)
 {
     HRESULT hres = S_OK;
@@ -407,7 +442,7 @@ static HRESULT compile_memberid_expression(compiler_ctx_t *ctx, expression_t *ex
     case EXPR_IDENT: {
         identifier_expression_t *ident_expr = (identifier_expression_t*)expr;
 
     case EXPR_IDENT: {
         identifier_expression_t *ident_expr = (identifier_expression_t*)expr;
 
-        hres = push_instr_bstr_uint(ctx, OP_identid, ident_expr->identifier, flags);
+        hres = emit_identifier_ref(ctx, ident_expr->identifier, flags);
         break;
     }
     case EXPR_ARRAY: {
         break;
     }
     case EXPR_ARRAY: {
@@ -866,9 +901,7 @@ static HRESULT compile_object_literal(compiler_ctx_t *ctx, property_value_expres
 
 static HRESULT compile_function_expression(compiler_ctx_t *ctx, function_expression_t *expr, BOOL emit_ret)
 {
 
 static HRESULT compile_function_expression(compiler_ctx_t *ctx, function_expression_t *expr, BOOL emit_ret)
 {
-    unsigned func_id = ctx->func->func_cnt++;
-    ctx->func_tail = ctx->func_tail ? (ctx->func_tail->next = expr) : (ctx->func_head = expr);
-    return emit_ret ? push_instr_uint(ctx, OP_func, func_id) : S_OK;
+    return emit_ret ? push_instr_uint(ctx, OP_func, expr->func_id) : S_OK;
 }
 
 static HRESULT compile_expression(compiler_ctx_t *ctx, expression_t *expr, BOOL emit_ret)
 }
 
 static HRESULT compile_expression(compiler_ctx_t *ctx, expression_t *expr, BOOL emit_ret)
@@ -961,7 +994,7 @@ static HRESULT compile_expression(compiler_ctx_t *ctx, expression_t *expr, BOOL
         hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_gteq);
         break;
     case EXPR_IDENT:
         hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_gteq);
         break;
     case EXPR_IDENT:
-        hres = push_instr_bstr(ctx, OP_ident, ((identifier_expression_t*)expr)->identifier);
+        hres = emit_identifier(ctx, ((identifier_expression_t*)expr)->identifier);
         break;
     case EXPR_IN:
         hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_in);
         break;
     case EXPR_IN:
         hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_in);
@@ -1084,25 +1117,22 @@ static HRESULT compile_variable_list(compiler_ctx_t *ctx, variable_declaration_t
 
     assert(list != NULL);
 
 
     assert(list != NULL);
 
-    if(ctx->var_tail)
-        ctx->var_tail->global_next = list;
-    else
-        ctx->var_head = list;
-
     for(iter = list; iter; iter = iter->next) {
     for(iter = list; iter; iter = iter->next) {
-        ctx->func->var_cnt++;
-        iter->global_next = iter->next;
-        if(!iter->next)
-            ctx->var_tail = iter;
-
         if(!iter->expr)
             continue;
 
         if(!iter->expr)
             continue;
 
+        hres = emit_identifier_ref(ctx, iter->identifier, 0);
+        if(FAILED(hres))
+            return hres;
+
         hres = compile_expression(ctx, iter->expr, TRUE);
         if(FAILED(hres))
             return hres;
 
         hres = compile_expression(ctx, iter->expr, TRUE);
         if(FAILED(hres))
             return hres;
 
-        hres = push_instr_bstr(ctx, OP_var_set, iter->identifier);
+        if(!push_instr(ctx, OP_assign))
+            return E_OUTOFMEMORY;
+
+        hres = push_instr_uint(ctx, OP_pop, 1);
         if(FAILED(hres))
             return hres;
     }
         if(FAILED(hres))
             return hres;
     }
@@ -1300,7 +1330,7 @@ static HRESULT compile_forin_statement(compiler_ctx_t *ctx, forin_statement_t *s
         return hres;
 
     if(stat->variable) {
         return hres;
 
     if(stat->variable) {
-        hres = push_instr_bstr_uint(ctx, OP_identid, stat->variable->identifier, fdexNameEnsure);
+        hres = emit_identifier_ref(ctx, stat->variable->identifier, fdexNameEnsure);
         if(FAILED(hres))
             return hres;
     }else if(is_memberid_expr(stat->expr->type)) {
         if(FAILED(hres))
             return hres;
     }else if(is_memberid_expr(stat->expr->type)) {
@@ -1774,6 +1804,393 @@ static HRESULT compile_statement(compiler_ctx_t *ctx, statement_ctx_t *stat_ctx,
     return hres;
 }
 
     return hres;
 }
 
+static int local_cmp(const void *key, const void *ref)
+{
+    return strcmpW((const WCHAR*)key, ((const local_ref_t*)ref)->name);
+}
+
+static inline local_ref_t *find_local(compiler_ctx_t *ctx, const WCHAR *name)
+{
+    return bsearch(name, ctx->locals_buf, ctx->locals_cnt, sizeof(*ctx->locals_buf), local_cmp);
+}
+
+static BOOL alloc_local(compiler_ctx_t *ctx, BSTR name, int ref)
+{
+    unsigned i;
+
+    if(!ctx->locals_buf_size) {
+        ctx->locals_buf = heap_alloc(4 * sizeof(*ctx->locals_buf));
+        if(!ctx->locals_buf)
+            return FALSE;
+        ctx->locals_buf_size = 4;
+    }else if(ctx->locals_buf_size == ctx->locals_cnt) {
+        local_ref_t *new_buf = heap_realloc(ctx->locals_buf, ctx->locals_buf_size * 2 * sizeof(*ctx->locals_buf));
+        if(!new_buf)
+            return FALSE;
+        ctx->locals_buf = new_buf;
+        ctx->locals_buf_size *= 2;
+    }
+
+    for(i = 0; i < ctx->locals_cnt; i++) {
+        if(strcmpW(ctx->locals_buf[i].name, name) > 0) {
+            memmove(ctx->locals_buf + i+1, ctx->locals_buf + i, (ctx->locals_cnt - i) * sizeof(*ctx->locals_buf));
+            break;
+        }
+    }
+
+    ctx->locals_buf[i].name = name;
+    ctx->locals_buf[i].ref = ref;
+    ctx->locals_cnt++;
+    return TRUE;
+}
+
+static BOOL alloc_variable(compiler_ctx_t *ctx, const WCHAR *name)
+{
+    BSTR ident;
+
+    if(find_local(ctx, name))
+        return TRUE;
+
+    ident = compiler_alloc_bstr(ctx, name);
+    if(!ident)
+        return FALSE;
+
+    return alloc_local(ctx, ident, ctx->func->var_cnt++);
+}
+
+static BOOL visit_function_expression(compiler_ctx_t *ctx, function_expression_t *expr)
+{
+    expr->func_id = ctx->func->func_cnt++;
+    ctx->func_tail = ctx->func_tail ? (ctx->func_tail->next = expr) : (ctx->func_head = expr);
+
+    return !expr->identifier || expr->event_target || alloc_variable(ctx, expr->identifier);
+}
+
+static HRESULT visit_expression(compiler_ctx_t *ctx, expression_t *expr)
+{
+    HRESULT hres = S_OK;
+
+    switch(expr->type) {
+    case EXPR_ADD:
+    case EXPR_AND:
+    case EXPR_ARRAY:
+    case EXPR_ASSIGN:
+    case EXPR_ASSIGNADD:
+    case EXPR_ASSIGNAND:
+    case EXPR_ASSIGNSUB:
+    case EXPR_ASSIGNMUL:
+    case EXPR_ASSIGNDIV:
+    case EXPR_ASSIGNMOD:
+    case EXPR_ASSIGNOR:
+    case EXPR_ASSIGNLSHIFT:
+    case EXPR_ASSIGNRSHIFT:
+    case EXPR_ASSIGNRRSHIFT:
+    case EXPR_ASSIGNXOR:
+    case EXPR_BAND:
+    case EXPR_BOR:
+    case EXPR_COMMA:
+    case EXPR_DIV:
+    case EXPR_EQ:
+    case EXPR_EQEQ:
+    case EXPR_GREATER:
+    case EXPR_GREATEREQ:
+    case EXPR_IN:
+    case EXPR_INSTANCEOF:
+    case EXPR_LESS:
+    case EXPR_LESSEQ:
+    case EXPR_LSHIFT:
+    case EXPR_MOD:
+    case EXPR_MUL:
+    case EXPR_NOTEQ:
+    case EXPR_NOTEQEQ:
+    case EXPR_OR:
+    case EXPR_RSHIFT:
+    case EXPR_RRSHIFT:
+    case EXPR_SUB:
+    case EXPR_BXOR: {
+        binary_expression_t *binary_expr = (binary_expression_t*)expr;
+
+        hres = visit_expression(ctx, binary_expr->expression1);
+        if(FAILED(hres))
+            return hres;
+
+        hres = visit_expression(ctx, binary_expr->expression2);
+        break;
+    }
+    case EXPR_BITNEG:
+    case EXPR_DELETE:
+    case EXPR_LOGNEG:
+    case EXPR_MINUS:
+    case EXPR_PLUS:
+    case EXPR_POSTDEC:
+    case EXPR_POSTINC:
+    case EXPR_PREDEC:
+    case EXPR_PREINC:
+    case EXPR_TYPEOF:
+    case EXPR_VOID:
+        hres = visit_expression(ctx, ((unary_expression_t*)expr)->expression);
+        break;
+    case EXPR_IDENT:
+    case EXPR_LITERAL:
+    case EXPR_THIS:
+        break;
+    case EXPR_ARRAYLIT: {
+        array_literal_expression_t *array_expr = (array_literal_expression_t*)expr;
+        array_element_t *iter;
+
+        for(iter = array_expr->element_list; iter; iter = iter->next) {
+            hres = visit_expression(ctx, iter->expr);
+            if(FAILED(hres))
+                return hres;
+        }
+        break;
+    }
+    case EXPR_CALL:
+    case EXPR_NEW: {
+        call_expression_t *call_expr = (call_expression_t*)expr;
+        argument_t *arg;
+
+        hres = visit_expression(ctx, call_expr->expression);
+        if(FAILED(hres))
+            return hres;
+
+        for(arg = call_expr->argument_list; arg; arg = arg->next) {
+            hres = visit_expression(ctx, arg->expr);
+            if(FAILED(hres))
+                return hres;
+        }
+        break;
+    }
+    case EXPR_COND: {
+        conditional_expression_t *cond_expr = (conditional_expression_t*)expr;
+
+        hres = visit_expression(ctx, cond_expr->expression);
+        if(FAILED(hres))
+            return hres;
+
+        hres = visit_expression(ctx, cond_expr->true_expression);
+        if(FAILED(hres))
+            return hres;
+
+        hres = visit_expression(ctx, cond_expr->false_expression);
+        break;
+    }
+    case EXPR_FUNC:
+        visit_function_expression(ctx, (function_expression_t*)expr);
+        break;
+    case EXPR_MEMBER:
+        hres = visit_expression(ctx, ((member_expression_t*)expr)->expression);
+        break;
+    case EXPR_PROPVAL: {
+        prop_val_t *iter;
+        for(iter = ((property_value_expression_t*)expr)->property_list; iter; iter = iter->next) {
+            hres = visit_expression(ctx, iter->value);
+            if(FAILED(hres))
+                return hres;
+        }
+        break;
+    }
+    DEFAULT_UNREACHABLE;
+    }
+
+    return hres;
+}
+
+static HRESULT visit_variable_list(compiler_ctx_t *ctx, variable_declaration_t *list)
+{
+    variable_declaration_t *iter;
+    HRESULT hres;
+
+    for(iter = list; iter; iter = iter->next) {
+        if(!alloc_variable(ctx, iter->identifier))
+            return E_OUTOFMEMORY;
+
+        if(iter->expr) {
+            hres = visit_expression(ctx, iter->expr);
+            if(FAILED(hres))
+                return hres;
+        }
+    }
+
+    return S_OK;
+}
+
+static HRESULT visit_statement(compiler_ctx_t*,statement_t*);
+
+static HRESULT visit_block_statement(compiler_ctx_t *ctx, statement_t *iter)
+{
+    HRESULT hres;
+
+    while(iter) {
+        hres = visit_statement(ctx, iter);
+        if(FAILED(hres))
+            return hres;
+
+        iter = iter->next;
+    }
+
+    return S_OK;
+}
+
+static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat)
+{
+    HRESULT hres = S_OK;
+
+    switch(stat->type) {
+    case STAT_BLOCK:
+        hres = visit_block_statement(ctx, ((block_statement_t*)stat)->stat_list);
+        break;
+    case STAT_BREAK:
+    case STAT_CONTINUE:
+    case STAT_EMPTY:
+        break;
+    case STAT_EXPR:
+    case STAT_RETURN:
+    case STAT_THROW: {
+        expression_statement_t *expr_stat = (expression_statement_t*)stat;
+        if(expr_stat->expr)
+            hres = visit_expression(ctx, expr_stat->expr);
+        break;
+    }
+    case STAT_FOR: {
+        for_statement_t *for_stat = (for_statement_t*)stat;
+
+        if(for_stat->variable_list)
+            hres = visit_variable_list(ctx, for_stat->variable_list);
+        else if(for_stat->begin_expr)
+            hres = visit_expression(ctx, for_stat->begin_expr);
+        if(FAILED(hres))
+            break;
+
+        if(for_stat->expr) {
+            hres = visit_expression(ctx, for_stat->expr);
+            if(FAILED(hres))
+                break;
+        }
+
+        hres = visit_statement(ctx, for_stat->statement);
+        if(FAILED(hres))
+            break;
+
+        if(for_stat->end_expr)
+            hres = visit_expression(ctx, for_stat->end_expr);
+        break;
+    }
+    case STAT_FORIN:  {
+        forin_statement_t *forin_stat = (forin_statement_t*)stat;
+
+        if(forin_stat->variable) {
+            hres = visit_variable_list(ctx, forin_stat->variable);
+            if(FAILED(hres))
+                break;
+        }
+
+        hres = visit_expression(ctx, forin_stat->in_expr);
+        if(FAILED(hres))
+            return hres;
+
+        if(forin_stat->expr) {
+            hres = visit_expression(ctx, forin_stat->expr);
+            if(FAILED(hres))
+                return hres;
+        }
+
+        hres = visit_statement(ctx, forin_stat->statement);
+        break;
+    }
+    case STAT_IF: {
+        if_statement_t *if_stat = (if_statement_t*)stat;
+
+        hres = visit_expression(ctx, if_stat->expr);
+        if(FAILED(hres))
+            return hres;
+
+        hres = visit_statement(ctx, if_stat->if_stat);
+        if(FAILED(hres))
+            return hres;
+
+        if(if_stat->else_stat)
+            hres = visit_statement(ctx, if_stat->else_stat);
+        break;
+    }
+    case STAT_LABEL:
+        hres = visit_statement(ctx, ((labelled_statement_t*)stat)->statement);
+        break;
+    case STAT_SWITCH: {
+        switch_statement_t *switch_stat = (switch_statement_t*)stat;
+        statement_t *stat_iter;
+        case_clausule_t *iter;
+
+        hres = visit_expression(ctx, switch_stat->expr);
+        if(FAILED(hres))
+            return hres;
+
+        for(iter = switch_stat->case_list; iter; iter = iter->next) {
+            if(!iter->expr)
+                continue;
+            hres = visit_expression(ctx, iter->expr);
+            if(FAILED(hres))
+                return hres;
+        }
+
+        for(iter = switch_stat->case_list; iter; iter = iter->next) {
+            while(iter->next && iter->next->stat == iter->stat)
+                iter = iter->next;
+            for(stat_iter = iter->stat; stat_iter && (!iter->next || iter->next->stat != stat_iter);
+                stat_iter = stat_iter->next) {
+                hres = visit_statement(ctx, stat_iter);
+                if(FAILED(hres))
+                    return hres;
+            }
+        }
+        break;
+    }
+    case STAT_TRY: {
+        try_statement_t *try_stat = (try_statement_t*)stat;
+
+        hres = visit_statement(ctx, try_stat->try_statement);
+        if(FAILED(hres))
+            return hres;
+
+        if(try_stat->catch_block) {
+            hres = visit_statement(ctx, try_stat->catch_block->statement);
+            if(FAILED(hres))
+                return hres;
+        }
+
+        if(try_stat->finally_statement)
+            hres = visit_statement(ctx, try_stat->finally_statement);
+        break;
+    }
+    case STAT_VAR:
+        hres = visit_variable_list(ctx, ((var_statement_t*)stat)->variable_list);
+        break;
+    case STAT_WHILE: {
+        while_statement_t *while_stat = (while_statement_t*)stat;
+
+        hres = visit_expression(ctx, while_stat->expr);
+        if(FAILED(hres))
+            return hres;
+
+        hres = visit_statement(ctx, while_stat->statement);
+        break;
+    }
+    case STAT_WITH: {
+        with_statement_t *with_stat = (with_statement_t*)stat;
+
+        hres = visit_expression(ctx, with_stat->expr);
+        if(FAILED(hres))
+            return hres;
+
+        hres = visit_statement(ctx, with_stat->statement);
+        break;
+    }
+    DEFAULT_UNREACHABLE;
+    }
+
+    return hres;
+}
+
 static void resolve_labels(compiler_ctx_t *ctx, unsigned off)
 {
     instr_t *instr;
 static void resolve_labels(compiler_ctx_t *ctx, unsigned off)
 {
     instr_t *instr;
@@ -1838,35 +2255,20 @@ static HRESULT init_code(compiler_ctx_t *compiler, const WCHAR *source)
 static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source, function_expression_t *func_expr,
         BOOL from_eval, function_code_t *func)
 {
 static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source, function_expression_t *func_expr,
         BOOL from_eval, function_code_t *func)
 {
-    variable_declaration_t *var_iter;
     function_expression_t *iter;
     function_expression_t *iter;
-    unsigned off, i;
+    unsigned off, i, j;
     HRESULT hres;
 
     TRACE("\n");
 
     HRESULT hres;
 
     TRACE("\n");
 
-    ctx->var_head = ctx->var_tail = NULL;
     ctx->func_head = ctx->func_tail = NULL;
     ctx->from_eval = from_eval;
     ctx->func_head = ctx->func_tail = NULL;
     ctx->from_eval = from_eval;
-
-    off = ctx->code_off;
     ctx->func = func;
     ctx->func = func;
-    hres = compile_block_statement(ctx, source->statement);
-    if(FAILED(hres))
-        return hres;
-
-    resolve_labels(ctx, off);
-
-    hres = push_instr_uint(ctx, OP_ret, !from_eval);
-    if(FAILED(hres))
-        return hres;
-
-    if(TRACE_ON(jscript_disas))
-        dump_code(ctx, off);
-
-    func->instr_off = off;
+    ctx->locals_cnt = 0;
 
     if(func_expr) {
 
     if(func_expr) {
+        parameter_t *param_iter;
+
         if(func_expr->identifier) {
             func->name = compiler_alloc_bstr(ctx, func_expr->identifier);
             if(!func->name)
         if(func_expr->identifier) {
             func->name = compiler_alloc_bstr(ctx, func_expr->identifier);
             if(!func->name)
@@ -1878,10 +2280,6 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
             if(!func->event_target)
                 return E_OUTOFMEMORY;
         }
             if(!func->event_target)
                 return E_OUTOFMEMORY;
         }
-    }
-
-    if(func_expr) {
-        parameter_t *param_iter;
 
         func->source = func_expr->src_str;
         func->source_len = func_expr->src_len;
 
         func->source = func_expr->src_str;
         func->source_len = func_expr->src_len;
@@ -1900,27 +2298,69 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
         }
     }
 
         }
     }
 
+    for(i = 0; i < func->param_cnt; i++) {
+        if(!find_local(ctx, func->params[i]) && !alloc_local(ctx, func->params[i], -i-1))
+            return E_OUTOFMEMORY;
+    }
+
+    hres = visit_block_statement(ctx, source->statement);
+    if(FAILED(hres))
+        return hres;
+
+    func->locals = compiler_alloc(ctx->code, ctx->locals_cnt * sizeof(*func->locals));
+    if(!func->locals)
+        return E_OUTOFMEMORY;
+    func->locals_cnt = ctx->locals_cnt;
+    memcpy(func->locals, ctx->locals_buf, func->locals_cnt * sizeof(*func->locals));
+
     func->variables = compiler_alloc(ctx->code, func->var_cnt * sizeof(*func->variables));
     if(!func->variables)
         return E_OUTOFMEMORY;
 
     func->variables = compiler_alloc(ctx->code, func->var_cnt * sizeof(*func->variables));
     if(!func->variables)
         return E_OUTOFMEMORY;
 
-    for(var_iter = ctx->var_head, i=0; var_iter; var_iter = var_iter->global_next, i++) {
-        func->variables[i] = compiler_alloc_bstr(ctx, var_iter->identifier);
-        if(!func->variables[i])
-            return E_OUTOFMEMORY;
+    for(i = 0, j = 0; i < func->locals_cnt; i++) {
+        if(func->locals[i].ref < 0)
+            continue; /* skip arguments */
+        func->variables[func->locals[i].ref].name = func->locals[i].name;
+        func->variables[func->locals[i].ref].func_id = -1;
+        j++;
     }
 
     }
 
-    assert(i == func->var_cnt);
+    assert(j == func->var_cnt);
 
     func->funcs = compiler_alloc(ctx->code, func->func_cnt * sizeof(*func->funcs));
     if(!func->funcs)
         return E_OUTOFMEMORY;
     memset(func->funcs, 0, func->func_cnt * sizeof(*func->funcs));
 
 
     func->funcs = compiler_alloc(ctx->code, func->func_cnt * sizeof(*func->funcs));
     if(!func->funcs)
         return E_OUTOFMEMORY;
     memset(func->funcs, 0, func->func_cnt * sizeof(*func->funcs));
 
+    off = ctx->code_off;
+    hres = compile_block_statement(ctx, source->statement);
+    if(FAILED(hres))
+        return hres;
+
+    resolve_labels(ctx, off);
+
+    hres = push_instr_uint(ctx, OP_ret, !from_eval);
+    if(FAILED(hres))
+        return hres;
+
+    if(TRACE_ON(jscript_disas))
+        dump_code(ctx, off);
+
+    func->instr_off = off;
+
     for(iter = ctx->func_head, i=0; iter; iter = iter->next, i++) {
         hres = compile_function(ctx, iter->source_elements, iter, FALSE, func->funcs+i);
         if(FAILED(hres))
             return hres;
     for(iter = ctx->func_head, i=0; iter; iter = iter->next, i++) {
         hres = compile_function(ctx, iter->source_elements, iter, FALSE, func->funcs+i);
         if(FAILED(hres))
             return hres;
+
+        TRACE("[%d] func %s\n", i, debugstr_w(func->funcs[i].name));
+        if(func->funcs[i].name && !func->funcs[i].event_target) {
+            local_ref_t *local_ref = lookup_local(func, func->funcs[i].name);
+            func->funcs[i].local_ref = local_ref->ref;
+            TRACE("found ref %s %d for %s\n", debugstr_w(local_ref->name), local_ref->ref, debugstr_w(func->funcs[i].name));
+            if(local_ref->ref >= 0)
+                func->variables[local_ref->ref].func_id = i;
+        }
     }
 
     assert(i == func->func_cnt);
     }
 
     assert(i == func->func_cnt);
@@ -2030,6 +2470,7 @@ HRESULT compile_script(script_ctx_t *ctx, const WCHAR *code, const WCHAR *args,
 
     hres = compile_function(&compiler, compiler.parser->source, NULL, from_eval, &compiler.code->global_code);
     parser_release(compiler.parser);
 
     hres = compile_function(&compiler, compiler.parser->source, NULL, from_eval, &compiler.code->global_code);
     parser_release(compiler.parser);
+    heap_free(compiler.locals_buf);
     if(FAILED(hres)) {
         release_bytecode(compiler.code);
         return hres;
     if(FAILED(hres)) {
         release_bytecode(compiler.code);
         return hres;
index 85dc74d..a6c14d6 100644 (file)
 
 #include "jscript.h"
 
 
 #include "jscript.h"
 
-/*
- * This IID is used to get jsdisp_t objecto from interface.
- * We might consider using private interface instead.
- */
-static const IID IID_IDispatchJS =
-        {0x719c3050,0xf9d3,0x11cf,{0xa4,0x93,0x00,0x40,0x05,0x23,0xa8,0xa6}};
-
 #define FDEX_VERSION_MASK 0xf0000000
 #define GOLDEN_RATIO 0x9E3779B9U
 
 #define FDEX_VERSION_MASK 0xf0000000
 #define GOLDEN_RATIO 0x9E3779B9U
 
@@ -491,10 +484,8 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val, IServi
     TRACE("%s = %s\n", debugstr_w(prop->name), debugstr_jsval(val));
 
     hres = jsval_copy(val, &prop->u.val);
     TRACE("%s = %s\n", debugstr_w(prop->name), debugstr_jsval(val));
 
     hres = jsval_copy(val, &prop->u.val);
-    if(FAILED(hres)) {
-        prop->u.val = jsval_undefined();
+    if(FAILED(hres))
         return hres;
         return hres;
-    }
 
     if(This->builtin_info->on_put)
         This->builtin_info->on_put(This, prop->name);
 
     if(This->builtin_info->on_put)
         This->builtin_info->on_put(This, prop->name);
@@ -558,11 +549,6 @@ static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid,
     }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
         TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
         *ppv = &This->IDispatchEx_iface;
     }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
         TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
         *ppv = &This->IDispatchEx_iface;
-    }else if(IsEqualGUID(&IID_IDispatchJS, riid)) {
-        TRACE("(%p)->(IID_IDispatchJS %p)\n", This, ppv);
-        jsdisp_addref(This);
-        *ppv = This;
-        return S_OK;
     }else {
         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
         *ppv = NULL;
     }else {
         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
         *ppv = NULL;
@@ -584,6 +570,7 @@ static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
 {
     jsdisp_t *This = impl_from_IDispatchEx(iface);
     ULONG ref = --This->ref;
 {
     jsdisp_t *This = impl_from_IDispatchEx(iface);
     ULONG ref = --This->ref;
+    TRACE("(%p) ref=%d\n", This, ref);
     if(!ref)
         jsdisp_free(This);
     return ref;
     if(!ref)
         jsdisp_free(This);
     return ref;
@@ -1007,7 +994,7 @@ HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const built
         }
 
         if(is_object_instance(val))
         }
 
         if(is_object_instance(val))
-            prot = iface_to_jsdisp((IUnknown*)get_object(val));
+            prot = iface_to_jsdisp(get_object(val));
         jsval_release(val);
     }
 
         jsval_release(val);
     }
 
@@ -1018,16 +1005,11 @@ HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const built
     return hres;
 }
 
     return hres;
 }
 
-jsdisp_t *iface_to_jsdisp(IUnknown *iface)
+jsdisp_t *iface_to_jsdisp(IDispatch *iface)
 {
 {
-    jsdisp_t *ret;
-    HRESULT hres;
-
-    hres = IUnknown_QueryInterface(iface, &IID_IDispatchJS, (void**)&ret);
-    if(FAILED(hres))
-        return NULL;
-
-    return ret;
+    return iface->lpVtbl == (const IDispatchVtbl*)&DispatchExVtbl
+        ? jsdisp_addref( impl_from_IDispatchEx((IDispatchEx*)iface))
+        : NULL;
 }
 
 HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID *id)
 }
 
 HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID *id)
@@ -1107,7 +1089,7 @@ HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, uns
     unsigned i;
     HRESULT hres;
 
     unsigned i;
     HRESULT hres;
 
-    jsdisp = iface_to_jsdisp((IUnknown*)disp);
+    jsdisp = iface_to_jsdisp(disp);
     if(jsdisp) {
         if(flags & DISPATCH_PROPERTYPUT) {
             FIXME("disp_call(propput) on builtin object\n");
     if(jsdisp) {
         if(flags & DISPATCH_PROPERTYPUT) {
             FIXME("disp_call(propput) on builtin object\n");
@@ -1200,7 +1182,7 @@ HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, IDispatch *jsthis, W
 
     assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT|DISPATCH_JSCRIPT_INTERNAL_MASK)));
 
 
     assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT|DISPATCH_JSCRIPT_INTERNAL_MASK)));
 
-    jsdisp = iface_to_jsdisp((IUnknown*)disp);
+    jsdisp = iface_to_jsdisp(disp);
     if(jsdisp) {
         hres = jsdisp_call_value(jsdisp, jsthis, flags, argc, argv, r);
         jsdisp_release(jsdisp);
     if(jsdisp) {
         hres = jsdisp_call_value(jsdisp, jsthis, flags, argc, argv, r);
         jsdisp_release(jsdisp);
@@ -1339,7 +1321,7 @@ HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val)
     jsdisp_t *jsdisp;
     HRESULT hres;
 
     jsdisp_t *jsdisp;
     HRESULT hres;
 
-    jsdisp = iface_to_jsdisp((IUnknown*)disp);
+    jsdisp = iface_to_jsdisp(disp);
     if(jsdisp) {
         dispex_prop_t *prop;
 
     if(jsdisp) {
         dispex_prop_t *prop;
 
@@ -1444,7 +1426,7 @@ HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t *val
     VARIANT var;
     HRESULT hres;
 
     VARIANT var;
     HRESULT hres;
 
-    jsdisp = iface_to_jsdisp((IUnknown*)disp);
+    jsdisp = iface_to_jsdisp(disp);
     if(jsdisp) {
         hres = jsdisp_propget(jsdisp, id, val);
         jsdisp_release(jsdisp);
     if(jsdisp) {
         hres = jsdisp_propget(jsdisp, id, val);
         jsdisp_release(jsdisp);
@@ -1495,7 +1477,7 @@ HRESULT disp_delete(IDispatch *disp, DISPID id, BOOL *ret)
     jsdisp_t *jsdisp;
     HRESULT hres;
 
     jsdisp_t *jsdisp;
     HRESULT hres;
 
-    jsdisp = iface_to_jsdisp((IUnknown*)disp);
+    jsdisp = iface_to_jsdisp(disp);
     if(jsdisp) {
         dispex_prop_t *prop;
 
     if(jsdisp) {
         dispex_prop_t *prop;
 
@@ -1531,7 +1513,7 @@ HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL
     BSTR bstr;
     HRESULT hres;
 
     BSTR bstr;
     HRESULT hres;
 
-    jsdisp = iface_to_jsdisp((IUnknown*)disp);
+    jsdisp = iface_to_jsdisp(disp);
     if(jsdisp) {
         dispex_prop_t *prop;
         const WCHAR *ptr;
     if(jsdisp) {
         dispex_prop_t *prop;
         const WCHAR *ptr;
index 08b7049..1a4086a 100644 (file)
@@ -39,6 +39,7 @@ typedef struct {
     enum {
         EXPRVAL_JSVAL,
         EXPRVAL_IDREF,
     enum {
         EXPRVAL_JSVAL,
         EXPRVAL_IDREF,
+        EXPRVAL_STACK_REF,
         EXPRVAL_INVALID
     } type;
     union {
         EXPRVAL_INVALID
     } type;
     union {
@@ -47,6 +48,8 @@ typedef struct {
             IDispatch *disp;
             DISPID id;
         } idref;
             IDispatch *disp;
             DISPID id;
         } idref;
+        unsigned off;
+        HRESULT hres;
     } u;
 } exprval_t;
 
     } u;
 } exprval_t;
 
@@ -85,27 +88,21 @@ static inline HRESULT stack_push_string(script_ctx_t *ctx, const WCHAR *str)
     return stack_push(ctx, jsval_string(v));
 }
 
     return stack_push(ctx, jsval_string(v));
 }
 
-static HRESULT stack_push_objid(script_ctx_t *ctx, IDispatch *disp, DISPID id)
-{
-    HRESULT hres;
-
-    hres = stack_push(ctx, jsval_disp(disp));
-    if(FAILED(hres))
-        return hres;
-
-    return stack_push(ctx, jsval_number(id));
-}
-
 static inline jsval_t stack_top(script_ctx_t *ctx)
 {
     assert(ctx->stack_top > ctx->call_ctx->stack_base);
     return ctx->stack[ctx->stack_top-1];
 }
 
 static inline jsval_t stack_top(script_ctx_t *ctx)
 {
     assert(ctx->stack_top > ctx->call_ctx->stack_base);
     return ctx->stack[ctx->stack_top-1];
 }
 
-static inline jsval_t stack_topn(script_ctx_t *ctx, unsigned n)
+static inline jsval_t *stack_top_ref(script_ctx_t *ctx, unsigned n)
 {
     assert(ctx->stack_top > ctx->call_ctx->stack_base+n);
 {
     assert(ctx->stack_top > ctx->call_ctx->stack_base+n);
-    return ctx->stack[ctx->stack_top-1-n];
+    return ctx->stack+ctx->stack_top-1-n;
+}
+
+static inline jsval_t stack_topn(script_ctx_t *ctx, unsigned n)
+{
+    return *stack_top_ref(ctx, n);
 }
 
 static inline jsval_t *stack_args(script_ctx_t *ctx, unsigned n)
 }
 
 static inline jsval_t *stack_args(script_ctx_t *ctx, unsigned n)
@@ -167,32 +164,178 @@ static inline HRESULT stack_pop_uint(script_ctx_t *ctx, DWORD *r)
     return to_uint32(ctx, stack_pop(ctx), r);
 }
 
     return to_uint32(ctx, stack_pop(ctx), r);
 }
 
-static inline IDispatch *stack_pop_objid(script_ctx_t *ctx, DISPID *id)
+static inline unsigned local_off(call_frame_t *frame, int ref)
 {
 {
-    assert(is_number(stack_top(ctx)) && is_object_instance(stack_topn(ctx, 1)));
+    return ref < 0
+        ? frame->arguments_off - ref-1
+        : frame->variables_off + ref;
+}
 
 
-    *id = get_number(stack_pop(ctx));
-    return get_object(stack_pop(ctx));
+static inline BSTR local_name(call_frame_t *frame, int ref)
+{
+    return ref < 0 ? frame->function->params[-ref-1] : frame->function->variables[ref].name;
 }
 
 }
 
-static inline IDispatch *stack_topn_objid(script_ctx_t *ctx, unsigned n, DISPID *id)
+/* Steals input reference even on failure. */
+static HRESULT stack_push_exprval(script_ctx_t *ctx, exprval_t *val)
 {
 {
-    assert(is_number(stack_topn(ctx, n)) && is_object_instance(stack_topn(ctx, n+1)));
+    HRESULT hres;
+
+    switch(val->type) {
+    case EXPRVAL_JSVAL:
+        assert(0);
+    case EXPRVAL_IDREF:
+        hres = stack_push(ctx, jsval_disp(val->u.idref.disp));
+        if(SUCCEEDED(hres))
+            hres = stack_push(ctx, jsval_number(val->u.idref.id));
+        else
+            IDispatch_Release(val->u.idref.disp);
+        return hres;
+    case EXPRVAL_STACK_REF:
+        hres = stack_push(ctx, jsval_number(val->u.off));
+        if(SUCCEEDED(hres))
+            hres = stack_push(ctx, jsval_undefined());
+        return hres;
+    case EXPRVAL_INVALID:
+        hres = stack_push(ctx, jsval_undefined());
+        if(SUCCEEDED(hres))
+            hres = stack_push(ctx, jsval_number(val->u.hres));
+        return hres;
+    }
 
 
-    *id = get_number(stack_topn(ctx, n));
-    return get_object(stack_topn(ctx, n+1));
+    assert(0);
+    return E_FAIL;
 }
 
 }
 
-static inline jsval_t steal_ret(call_frame_t *frame)
+static BOOL stack_topn_exprval(script_ctx_t *ctx, unsigned n, exprval_t *r)
 {
 {
-    jsval_t r = frame->ret;
-    frame->ret = jsval_undefined();
-    return r;
+    jsval_t v = stack_topn(ctx, n+1);
+
+    switch(jsval_type(v)) {
+    case JSV_NUMBER: {
+        call_frame_t *frame = ctx->call_ctx;
+        unsigned off = get_number(v);
+
+        if(!frame->base_scope->frame && off >= frame->arguments_off) {
+            DISPID id;
+            BSTR name;
+            HRESULT hres;
+
+            /* Got stack reference in deoptimized code. Need to convert it back to variable object reference. */
+
+            assert(off < frame->variables_off + frame->function->var_cnt);
+            name = off >= frame->variables_off
+                ? frame->function->variables[off - frame->variables_off].name
+                : frame->function->params[off - frame->arguments_off];
+            hres = jsdisp_get_id(ctx->call_ctx->base_scope->jsobj, name, 0, &id);
+            if(FAILED(hres)) {
+                r->type = EXPRVAL_INVALID;
+                r->u.hres = hres;
+                return FALSE;
+            }
+
+            *stack_top_ref(ctx, n+1) = jsval_obj(jsdisp_addref(frame->base_scope->jsobj));
+            *stack_top_ref(ctx, n) = jsval_number(id);
+            r->type = EXPRVAL_IDREF;
+            r->u.idref.disp = frame->base_scope->obj;
+            r->u.idref.id = id;
+            return TRUE;
+        }
+
+        r->type = EXPRVAL_STACK_REF;
+        r->u.off = off;
+        return TRUE;
+    }
+    case JSV_OBJECT:
+        r->type = EXPRVAL_IDREF;
+        r->u.idref.disp = get_object(v);
+        assert(is_number(stack_topn(ctx, n)));
+        r->u.idref.id = get_number(stack_topn(ctx, n));
+        return TRUE;
+    case JSV_UNDEFINED:
+        r->type = EXPRVAL_INVALID;
+        assert(is_number(stack_topn(ctx, n)));
+        r->u.hres = get_number(stack_topn(ctx, n));
+        return FALSE;
+    default:
+        assert(0);
+        return FALSE;
+    }
 }
 
 }
 
-static inline void clear_ret(call_frame_t *frame)
+static inline BOOL stack_pop_exprval(script_ctx_t *ctx, exprval_t *r)
 {
 {
-    jsval_release(steal_ret(frame));
+    BOOL ret = stack_topn_exprval(ctx, 0, r);
+    ctx->stack_top -= 2;
+    return ret;
+}
+
+static HRESULT exprval_propput(script_ctx_t *ctx, exprval_t *ref, jsval_t v)
+{
+    switch(ref->type) {
+    case EXPRVAL_STACK_REF: {
+        jsval_t *r = ctx->stack + ref->u.off;
+        jsval_release(*r);
+        return jsval_copy(v, r);
+    }
+    case EXPRVAL_IDREF:
+        return disp_propput(ctx, ref->u.idref.disp, ref->u.idref.id, v);
+    default:
+        assert(0);
+        return E_FAIL;
+    }
+}
+
+static HRESULT exprval_propget(script_ctx_t *ctx, exprval_t *ref, jsval_t *r)
+{
+    switch(ref->type) {
+    case EXPRVAL_STACK_REF:
+        return jsval_copy(ctx->stack[ref->u.off], r);
+    case EXPRVAL_IDREF:
+        return disp_propget(ctx, ref->u.idref.disp, ref->u.idref.id, r);
+    default:
+        assert(0);
+        return E_FAIL;
+    }
+}
+
+static HRESULT exprval_call(script_ctx_t *ctx, exprval_t *ref, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
+{
+    switch(ref->type) {
+    case EXPRVAL_STACK_REF: {
+        jsval_t v = ctx->stack[ref->u.off];
+
+        if(!is_object_instance(v)) {
+            FIXME("invoke %s\n", debugstr_jsval(v));
+            return E_FAIL;
+        }
+
+        return disp_call_value(ctx, get_object(v), NULL, flags, argc, argv, r);
+    }
+    case EXPRVAL_IDREF:
+        return disp_call(ctx, ref->u.idref.disp, ref->u.idref.id, flags, argc, argv, r);
+    default:
+        assert(0);
+        return E_FAIL;
+    }
+}
+
+/* ECMA-262 3rd Edition    8.7.1 */
+/* Steals input reference. */
+static HRESULT exprval_to_value(script_ctx_t *ctx, exprval_t *ref, jsval_t *r)
+{
+    HRESULT hres;
+
+    if(ref->type == EXPRVAL_JSVAL) {
+        *r = ref->u.val;
+        return S_OK;
+    }
+
+    hres = exprval_propget(ctx, ref, r);
+
+    if(ref->type == EXPRVAL_IDREF)
+        IDispatch_Release(ref->u.idref.disp);
+    return hres;
 }
 
 static void exprval_release(exprval_t *val)
 }
 
 static void exprval_release(exprval_t *val)
@@ -205,42 +348,40 @@ static void exprval_release(exprval_t *val)
         if(val->u.idref.disp)
             IDispatch_Release(val->u.idref.disp);
         return;
         if(val->u.idref.disp)
             IDispatch_Release(val->u.idref.disp);
         return;
+    case EXPRVAL_STACK_REF:
     case EXPRVAL_INVALID:
         return;
     }
 }
 
     case EXPRVAL_INVALID:
         return;
     }
 }
 
-/* ECMA-262 3rd Edition    8.7.1 */
-static HRESULT exprval_to_value(script_ctx_t *ctx, exprval_t *val, jsval_t *ret)
+static inline void exprval_set_exception(exprval_t *val, HRESULT hres)
 {
 {
-    switch(val->type) {
-    case EXPRVAL_JSVAL:
-        *ret = val->u.val;
-        val->u.val = jsval_undefined();
-        return S_OK;
-    case EXPRVAL_IDREF:
-        if(!val->u.idref.disp) {
-            FIXME("throw ReferenceError\n");
-            return E_FAIL;
-        }
-
-        return disp_propget(ctx, val->u.idref.disp, val->u.idref.id, ret);
-    case EXPRVAL_INVALID:
-        assert(0);
-    }
+    val->type = EXPRVAL_INVALID;
+    val->u.hres = hres;
+}
 
 
-    ERR("type %d\n", val->type);
-    return E_FAIL;
+static inline void exprval_set_disp_ref(exprval_t *ref, IDispatch *obj, DISPID id)
+{
+    ref->type = EXPRVAL_IDREF;
+#ifdef __REACTOS__ /* FIXME: Inspect */
+    IDispatch_AddRef(obj);
+    ref->u.idref.disp = obj;
+#else
+    IDispatch_AddRef(ref->u.idref.disp = obj);
+#endif
+    ref->u.idref.id = id;
 }
 
 }
 
-static void exprval_set_idref(exprval_t *val, IDispatch *disp, DISPID id)
+static inline jsval_t steal_ret(call_frame_t *frame)
 {
 {
-    val->type = EXPRVAL_IDREF;
-    val->u.idref.disp = disp;
-    val->u.idref.id = id;
+    jsval_t r = frame->ret;
+    frame->ret = jsval_undefined();
+    return r;
+}
 
 
-    if(disp)
-        IDispatch_AddRef(disp);
+static inline void clear_ret(call_frame_t *frame)
+{
+    jsval_release(steal_ret(frame));
 }
 
 HRESULT scope_push(scope_chain_t *scope, jsdisp_t *jsobj, IDispatch *obj, scope_chain_t **ret)
 }
 
 HRESULT scope_push(scope_chain_t *scope, jsdisp_t *jsobj, IDispatch *obj, scope_chain_t **ret)
@@ -256,13 +397,8 @@ HRESULT scope_push(scope_chain_t *scope, jsdisp_t *jsobj, IDispatch *obj, scope_
     IDispatch_AddRef(obj);
     new_scope->jsobj = jsobj;
     new_scope->obj = obj;
     IDispatch_AddRef(obj);
     new_scope->jsobj = jsobj;
     new_scope->obj = obj;
-
-    if(scope) {
-        scope_addref(scope);
-        new_scope->next = scope;
-    }else {
-        new_scope->next = NULL;
-    }
+    new_scope->frame = NULL;
+    new_scope->next = scope ? scope_addref(scope) : NULL;
 
     *ret = new_scope;
     return S_OK;
 
     *ret = new_scope;
     return S_OK;
@@ -303,7 +439,7 @@ static HRESULT disp_get_id(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name
     BSTR bstr;
     HRESULT hres;
 
     BSTR bstr;
     HRESULT hres;
 
-    jsdisp = iface_to_jsdisp((IUnknown*)disp);
+    jsdisp = iface_to_jsdisp(disp);
     if(jsdisp) {
         hres = jsdisp_get_id(jsdisp, name, flags, id);
         jsdisp_release(jsdisp);
     if(jsdisp) {
         hres = jsdisp_get_id(jsdisp, name, flags, id);
         jsdisp_release(jsdisp);
@@ -416,6 +552,41 @@ static HRESULT equal2_values(jsval_t lval, jsval_t rval, BOOL *ret)
     return S_OK;
 }
 
     return S_OK;
 }
 
+/*
+ * Transfers local variables from stack to variable object.
+ * It's slow, so we want to avoid it as much as possible.
+ */
+static HRESULT detach_variable_object(script_ctx_t *ctx, call_frame_t *frame, BOOL from_release)
+{
+    unsigned i;
+    HRESULT hres;
+
+    if(!frame->base_scope || !frame->base_scope->frame)
+        return S_OK;
+
+    TRACE("detaching %p\n", frame);
+
+    assert(frame == frame->base_scope->frame);
+    assert(frame->variable_obj == frame->base_scope->jsobj);
+
+    if(!from_release && !frame->arguments_obj) {
+        hres = setup_arguments_object(ctx, frame);
+        if(FAILED(hres))
+            return hres;
+    }
+
+    frame->base_scope->frame = NULL;
+
+    for(i = 0; i < frame->function->locals_cnt; i++) {
+        hres = jsdisp_propput_name(frame->variable_obj, frame->function->locals[i].name,
+                                   ctx->stack[local_off(frame, frame->function->locals[i].ref)]);
+        if(FAILED(hres))
+            return hres;
+    }
+
+    return S_OK;
+}
+
 static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
 {
     named_item_t *item;
 static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
 {
     named_item_t *item;
@@ -427,7 +598,7 @@ static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t
             hres = disp_get_id(ctx, item->disp, identifier, identifier, 0, &id);
             if(SUCCEEDED(hres)) {
                 if(ret)
             hres = disp_get_id(ctx, item->disp, identifier, identifier, 0, &id);
             if(SUCCEEDED(hres)) {
                 if(ret)
-                    exprval_set_idref(ret, item->disp, id);
+                    exprval_set_disp_ref(ret, item->disp, id);
                 return TRUE;
             }
         }
                 return TRUE;
             }
         }
@@ -436,6 +607,16 @@ static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t
     return FALSE;
 }
 
     return FALSE;
 }
 
+static int local_ref_cmp(const void *key, const void *ref)
+{
+    return strcmpW((const WCHAR*)key, ((const local_ref_t*)ref)->name);
+}
+
+local_ref_t *lookup_local(const function_code_t *function, const WCHAR *identifier)
+{
+    return bsearch(identifier, function->locals, function->locals_cnt, sizeof(*function->locals), local_ref_cmp);
+}
+
 /* ECMA-262 3rd Edition    10.1.4 */
 static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
 {
 /* ECMA-262 3rd Edition    10.1.4 */
 static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
 {
@@ -448,12 +629,30 @@ static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *re
 
     if(ctx->call_ctx) {
         for(scope = ctx->call_ctx->scope; scope; scope = scope->next) {
 
     if(ctx->call_ctx) {
         for(scope = ctx->call_ctx->scope; scope; scope = scope->next) {
+            if(scope->frame) {
+                function_code_t *func = scope->frame->function;
+                local_ref_t *ref = lookup_local(func, identifier);
+                static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0};
+
+                if(ref) {
+                    ret->type = EXPRVAL_STACK_REF;
+                    ret->u.off = local_off(scope->frame, ref->ref);
+                    TRACE("returning ref %d for %d\n", ret->u.off, ref->ref);
+                    return S_OK;
+                }
+
+                if(!strcmpW(identifier, argumentsW)) {
+                    hres = detach_variable_object(ctx, scope->frame, FALSE);
+                    if(FAILED(hres))
+                        return hres;
+                }
+            }
             if(scope->jsobj)
                 hres = jsdisp_get_id(scope->jsobj, identifier, fdexNameImplicit, &id);
             else
                 hres = disp_get_id(ctx, scope->obj, identifier, identifier, fdexNameImplicit, &id);
             if(SUCCEEDED(hres)) {
             if(scope->jsobj)
                 hres = jsdisp_get_id(scope->jsobj, identifier, fdexNameImplicit, &id);
             else
                 hres = disp_get_id(ctx, scope->obj, identifier, identifier, fdexNameImplicit, &id);
             if(SUCCEEDED(hres)) {
-                exprval_set_idref(ret, scope->obj, id);
+                exprval_set_disp_ref(ret, scope->obj, id);
                 return S_OK;
             }
         }
                 return S_OK;
             }
         }
@@ -461,7 +660,7 @@ static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *re
 
     hres = jsdisp_get_id(ctx->global, identifier, 0, &id);
     if(SUCCEEDED(hres)) {
 
     hres = jsdisp_get_id(ctx->global, identifier, 0, &id);
     if(SUCCEEDED(hres)) {
-        exprval_set_idref(ret, to_disp(ctx->global), id);
+        exprval_set_disp_ref(ret, to_disp(ctx->global), id);
         return S_OK;
     }
 
         return S_OK;
     }
 
@@ -498,7 +697,7 @@ static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *re
     if(lookup_global_members(ctx, identifier, ret))
         return S_OK;
 
     if(lookup_global_members(ctx, identifier, ret))
         return S_OK;
 
-    ret->type = EXPRVAL_INVALID;
+    exprval_set_exception(ret, JS_E_UNDEFINED_VARIABLE);
     return S_OK;
 }
 
     return S_OK;
 }
 
@@ -542,28 +741,14 @@ static inline void jmp_abs(script_ctx_t *ctx, unsigned dst)
     ctx->call_ctx->ip = dst;
 }
 
     ctx->call_ctx->ip = dst;
 }
 
-/* ECMA-262 3rd Edition    12.2 */
-static HRESULT interp_var_set(script_ctx_t *ctx)
-{
-    const BSTR name = get_op_bstr(ctx, 0);
-    jsval_t val;
-    HRESULT hres;
-
-    TRACE("%s\n", debugstr_w(name));
-
-    val = stack_pop(ctx);
-    hres = jsdisp_propput_name(ctx->call_ctx->variable_obj, name, val);
-    jsval_release(val);
-    return hres;
-}
-
 /* ECMA-262 3rd Edition    12.6.4 */
 static HRESULT interp_forin(script_ctx_t *ctx)
 {
     const HRESULT arg = get_op_uint(ctx, 0);
 /* ECMA-262 3rd Edition    12.6.4 */
 static HRESULT interp_forin(script_ctx_t *ctx)
 {
     const HRESULT arg = get_op_uint(ctx, 0);
-    IDispatch *var_obj, *obj = NULL;
+    IDispatch *obj = NULL;
     IDispatchEx *dispex;
     IDispatchEx *dispex;
-    DISPID id, var_id;
+    exprval_t prop_ref;
+    DISPID id;
     BSTR name = NULL;
     HRESULT hres;
 
     BSTR name = NULL;
     HRESULT hres;
 
@@ -572,9 +757,8 @@ static HRESULT interp_forin(script_ctx_t *ctx)
     assert(is_number(stack_top(ctx)));
     id = get_number(stack_top(ctx));
 
     assert(is_number(stack_top(ctx)));
     id = get_number(stack_top(ctx));
 
-    var_obj = stack_topn_objid(ctx, 1, &var_id);
-    if(!var_obj) {
-        FIXME("invalid ref\n");
+    if(!stack_topn_exprval(ctx, 1, &prop_ref)) {
+        FIXME("invalid ref: %08x\n", prop_ref.u.hres);
         return E_FAIL;
     }
 
         return E_FAIL;
     }
 
@@ -606,7 +790,7 @@ static HRESULT interp_forin(script_ctx_t *ctx)
         stack_pop(ctx);
         stack_push(ctx, jsval_number(id)); /* safe, just after pop() */
 
         stack_pop(ctx);
         stack_push(ctx, jsval_number(id)); /* safe, just after pop() */
 
-        hres = disp_propput(ctx, var_obj, var_id, jsval_string(str));
+        hres = exprval_propput(ctx, &prop_ref, jsval_string(str));
         jsstr_release(str);
         if(FAILED(hres))
             return hres;
         jsstr_release(str);
         if(FAILED(hres))
             return hres;
@@ -875,6 +1059,7 @@ static HRESULT interp_memberid(script_ctx_t *ctx)
     const WCHAR *name;
     jsstr_t *name_str;
     IDispatch *obj;
     const WCHAR *name;
     jsstr_t *name_str;
     IDispatch *obj;
+    exprval_t ref;
     DISPID id;
     HRESULT hres;
 
     DISPID id;
     HRESULT hres;
 
@@ -896,35 +1081,37 @@ static HRESULT interp_memberid(script_ctx_t *ctx)
 
     hres = disp_get_id(ctx, obj, name, NULL, arg, &id);
     jsstr_release(name_str);
 
     hres = disp_get_id(ctx, obj, name, NULL, arg, &id);
     jsstr_release(name_str);
-    if(FAILED(hres)) {
+    if(SUCCEEDED(hres)) {
+        ref.type = EXPRVAL_IDREF;
+        ref.u.idref.disp = obj;
+        ref.u.idref.id = id;
+    }else {
         IDispatch_Release(obj);
         if(hres == DISP_E_UNKNOWNNAME && !(arg & fdexNameEnsure)) {
         IDispatch_Release(obj);
         if(hres == DISP_E_UNKNOWNNAME && !(arg & fdexNameEnsure)) {
-            obj = NULL;
-            id = JS_E_INVALID_PROPERTY;
+            exprval_set_exception(&ref, JS_E_INVALID_PROPERTY);
+            hres = S_OK;
         }else {
             ERR("failed %08x\n", hres);
             return hres;
         }
     }
 
         }else {
             ERR("failed %08x\n", hres);
             return hres;
         }
     }
 
-    return stack_push_objid(ctx, obj, id);
+    return stack_push_exprval(ctx, &ref);
 }
 
 /* ECMA-262 3rd Edition    11.2.1 */
 static HRESULT interp_refval(script_ctx_t *ctx)
 {
 }
 
 /* ECMA-262 3rd Edition    11.2.1 */
 static HRESULT interp_refval(script_ctx_t *ctx)
 {
-    IDispatch *disp;
+    exprval_t ref;
     jsval_t v;
     jsval_t v;
-    DISPID id;
     HRESULT hres;
 
     TRACE("\n");
 
     HRESULT hres;
 
     TRACE("\n");
 
-    disp = stack_topn_objid(ctx, 0, &id);
-    if(!disp)
+    if(!stack_topn_exprval(ctx, 0, &ref))
         return throw_reference_error(ctx, JS_E_ILLEGAL_ASSIGN, NULL);
 
         return throw_reference_error(ctx, JS_E_ILLEGAL_ASSIGN, NULL);
 
-    hres = disp_propget(ctx, disp, id, &v);
+    hres = exprval_propget(ctx, &ref, &v);
     if(FAILED(hres))
         return hres;
 
     if(FAILED(hres))
         return hres;
 
@@ -981,17 +1168,15 @@ static HRESULT interp_call_member(script_ctx_t *ctx)
     const unsigned argn = get_op_uint(ctx, 0);
     const int do_ret = get_op_int(ctx, 1);
     call_frame_t *frame = ctx->call_ctx;
     const unsigned argn = get_op_uint(ctx, 0);
     const int do_ret = get_op_int(ctx, 1);
     call_frame_t *frame = ctx->call_ctx;
-    IDispatch *obj;
-    DISPID id;
+    exprval_t ref;
 
     TRACE("%d %d\n", argn, do_ret);
 
 
     TRACE("%d %d\n", argn, do_ret);
 
-    obj = stack_topn_objid(ctx, argn, &id);
-    if(!obj)
-        return throw_type_error(ctx, id, NULL);
+    if(!stack_topn_exprval(ctx, argn, &ref))
+        return throw_type_error(ctx, ref.u.hres, NULL);
 
     clear_ret(frame);
 
     clear_ret(frame);
-    return disp_call(ctx, obj, id, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
+    return exprval_call(ctx, &ref, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
             argn, stack_args(ctx, argn), do_ret ? &frame->ret : NULL);
 }
 
             argn, stack_args(ctx, argn), do_ret ? &frame->ret : NULL);
 }
 
@@ -1006,62 +1191,109 @@ static HRESULT interp_this(script_ctx_t *ctx)
     return stack_push(ctx, jsval_disp(frame->this_obj));
 }
 
     return stack_push(ctx, jsval_disp(frame->this_obj));
 }
 
-/* ECMA-262 3rd Edition    10.1.4 */
-static HRESULT interp_ident(script_ctx_t *ctx)
+static HRESULT interp_identifier_ref(script_ctx_t *ctx, BSTR identifier, unsigned flags)
 {
 {
-    const BSTR arg = get_op_bstr(ctx, 0);
     exprval_t exprval;
     exprval_t exprval;
-    jsval_t v;
     HRESULT hres;
 
     HRESULT hres;
 
-    TRACE("%s\n", debugstr_w(arg));
+    hres = identifier_eval(ctx, identifier, &exprval);
+    if(FAILED(hres))
+        return hres;
 
 
-    hres = identifier_eval(ctx, arg, &exprval);
+    if(exprval.type == EXPRVAL_INVALID && (flags & fdexNameEnsure)) {
+        DISPID id;
+
+        hres = jsdisp_get_id(ctx->global, identifier, fdexNameEnsure, &id);
+        if(FAILED(hres))
+            return hres;
+
+        exprval_set_disp_ref(&exprval, to_disp(ctx->global), id);
+    }
+
+    if(exprval.type == EXPRVAL_JSVAL || exprval.type == EXPRVAL_INVALID) {
+        WARN("invalid ref\n");
+        exprval_release(&exprval);
+        exprval_set_exception(&exprval, JS_E_OBJECT_EXPECTED);
+    }
+
+    return stack_push_exprval(ctx, &exprval);
+}
+
+static HRESULT identifier_value(script_ctx_t *ctx, BSTR identifier)
+{
+    exprval_t exprval;
+    jsval_t v;
+    HRESULT hres;
+
+    hres = identifier_eval(ctx, identifier, &exprval);
     if(FAILED(hres))
         return hres;
 
     if(exprval.type == EXPRVAL_INVALID)
     if(FAILED(hres))
         return hres;
 
     if(exprval.type == EXPRVAL_INVALID)
-        return throw_type_error(ctx, JS_E_UNDEFINED_VARIABLE, arg);
+        return throw_type_error(ctx, exprval.u.hres, identifier);
 
     hres = exprval_to_value(ctx, &exprval, &v);
 
     hres = exprval_to_value(ctx, &exprval, &v);
-    exprval_release(&exprval);
     if(FAILED(hres))
         return hres;
 
     return stack_push(ctx, v);
 }
 
     if(FAILED(hres))
         return hres;
 
     return stack_push(ctx, v);
 }
 
-/* ECMA-262 3rd Edition    10.1.4 */
-static HRESULT interp_identid(script_ctx_t *ctx)
+static HRESULT interp_local_ref(script_ctx_t *ctx)
 {
 {
-    const BSTR arg = get_op_bstr(ctx, 0);
+    const int arg = get_op_int(ctx, 0);
     const unsigned flags = get_op_uint(ctx, 1);
     const unsigned flags = get_op_uint(ctx, 1);
-    exprval_t exprval;
+    call_frame_t *frame = ctx->call_ctx;
+    exprval_t ref;
+
+    TRACE("%d\n", arg);
+
+    if(!frame->base_scope || !frame->base_scope->frame)
+        return interp_identifier_ref(ctx, local_name(frame, arg), flags);
+
+    ref.type = EXPRVAL_STACK_REF;
+    ref.u.off = local_off(frame, arg);
+    return stack_push_exprval(ctx, &ref);
+}
+
+static HRESULT interp_local(script_ctx_t *ctx)
+{
+    const int arg = get_op_int(ctx, 0);
+    call_frame_t *frame = ctx->call_ctx;
+    jsval_t copy;
     HRESULT hres;
 
     HRESULT hres;
 
-    TRACE("%s %x\n", debugstr_w(arg), flags);
+    TRACE("%d\n", arg);
 
 
-    hres = identifier_eval(ctx, arg, &exprval);
+    if(!frame->base_scope || !frame->base_scope->frame)
+        return identifier_value(ctx, local_name(frame, arg));
+
+    hres = jsval_copy(ctx->stack[local_off(frame, arg)], &copy);
     if(FAILED(hres))
         return hres;
 
     if(FAILED(hres))
         return hres;
 
-    if(exprval.type == EXPRVAL_INVALID && (flags & fdexNameEnsure)) {
-        DISPID id;
+    return stack_push(ctx, copy);
+}
 
 
-        hres = jsdisp_get_id(ctx->global, arg, fdexNameEnsure, &id);
-        if(FAILED(hres))
-            return hres;
+/* ECMA-262 3rd Edition    10.1.4 */
+static HRESULT interp_ident(script_ctx_t *ctx)
+{
+    const BSTR arg = get_op_bstr(ctx, 0);
 
 
-        exprval_set_idref(&exprval, to_disp(ctx->global), id);
-    }
+    TRACE("%s\n", debugstr_w(arg));
 
 
-    if(exprval.type != EXPRVAL_IDREF) {
-        WARN("invalid ref\n");
-        exprval_release(&exprval);
-        return stack_push_objid(ctx, NULL, JS_E_OBJECT_EXPECTED);
-    }
+    return identifier_value(ctx, arg);
+}
 
 
-    return stack_push_objid(ctx, exprval.u.idref.disp, exprval.u.idref.id);
+/* ECMA-262 3rd Edition    10.1.4 */
+static HRESULT interp_identid(script_ctx_t *ctx)
+{
+    const BSTR arg = get_op_bstr(ctx, 0);
+    const unsigned flags = get_op_uint(ctx, 1);
+
+    TRACE("%s %x\n", debugstr_w(arg), flags);
+
+    return interp_identifier_ref(ctx, arg, flags);
 }
 
 /* ECMA-262 3rd Edition    7.8.1 */
 }
 
 /* ECMA-262 3rd Edition    7.8.1 */
@@ -1310,7 +1542,7 @@ static HRESULT interp_instanceof(script_ctx_t *ctx)
         return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
     }
 
         return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
     }
 
-    obj = iface_to_jsdisp((IUnknown*)get_object(v));
+    obj = iface_to_jsdisp(get_object(v));
     IDispatch_Release(get_object(v));
     if(!obj) {
         FIXME("non-jsdisp objects not supported\n");
     IDispatch_Release(get_object(v));
     if(!obj) {
         FIXME("non-jsdisp objects not supported\n");
@@ -1330,7 +1562,7 @@ static HRESULT interp_instanceof(script_ctx_t *ctx)
 
     if(is_object_instance(prot)) {
         if(is_object_instance(v))
 
     if(is_object_instance(prot)) {
         if(is_object_instance(v))
-            tmp = iface_to_jsdisp((IUnknown*)get_object(v));
+            tmp = iface_to_jsdisp(get_object(v));
         for(iter = tmp; !ret && iter; iter = iter->prototype) {
             hres = disp_cmp(get_object(prot), to_disp(iter), &ret);
             if(FAILED(hres))
         for(iter = tmp; !ret && iter; iter = iter->prototype) {
             hres = disp_cmp(get_object(prot), to_disp(iter), &ret);
             if(FAILED(hres))
@@ -1591,6 +1823,9 @@ static HRESULT interp_delete_ident(script_ctx_t *ctx)
         return hres;
 
     switch(exprval.type) {
         return hres;
 
     switch(exprval.type) {
+    case EXPRVAL_STACK_REF:
+        ret = FALSE;
+        break;
     case EXPRVAL_IDREF:
         hres = disp_delete(exprval.u.idref.disp, exprval.u.idref.id, &ret);
         IDispatch_Release(exprval.u.idref.disp);
     case EXPRVAL_IDREF:
         hres = disp_delete(exprval.u.idref.disp, exprval.u.idref.id, &ret);
         IDispatch_Release(exprval.u.idref.disp);
@@ -1632,7 +1867,7 @@ static HRESULT typeof_string(jsval_t v, const WCHAR **ret)
     case JSV_OBJECT: {
         jsdisp_t *dispex;
 
     case JSV_OBJECT: {
         jsdisp_t *dispex;
 
-        if(get_object(v) && (dispex = iface_to_jsdisp((IUnknown*)get_object(v)))) {
+        if(get_object(v) && (dispex = iface_to_jsdisp(get_object(v)))) {
             *ret = is_class(dispex, JSCLASS_FUNCTION) ? functionW : objectW;
             jsdisp_release(dispex);
         }else {
             *ret = is_class(dispex, JSCLASS_FUNCTION) ? functionW : objectW;
             jsdisp_release(dispex);
         }else {
@@ -1661,19 +1896,17 @@ static HRESULT typeof_string(jsval_t v, const WCHAR **ret)
 static HRESULT interp_typeofid(script_ctx_t *ctx)
 {
     const WCHAR *ret;
 static HRESULT interp_typeofid(script_ctx_t *ctx)
 {
     const WCHAR *ret;
-    IDispatch *obj;
+    exprval_t ref;
     jsval_t v;
     jsval_t v;
-    DISPID id;
     HRESULT hres;
 
     TRACE("\n");
 
     HRESULT hres;
 
     TRACE("\n");
 
-    obj = stack_pop_objid(ctx, &id);
-    if(!obj)
+    if(!stack_pop_exprval(ctx, &ref))
         return stack_push(ctx, jsval_string(jsstr_undefined()));
 
         return stack_push(ctx, jsval_string(jsstr_undefined()));
 
-    hres = disp_propget(ctx, obj, id, &v);
-    IDispatch_Release(obj);
+    hres = exprval_propget(ctx, &ref, &v);
+    exprval_release(&ref);
     if(FAILED(hres))
         return stack_push_string(ctx, unknownW);
 
     if(FAILED(hres))
         return stack_push_string(ctx, unknownW);
 
@@ -1700,14 +1933,10 @@ static HRESULT interp_typeofident(script_ctx_t *ctx)
     if(FAILED(hres))
         return hres;
 
     if(FAILED(hres))
         return hres;
 
-    if(exprval.type == EXPRVAL_INVALID) {
-        hres = stack_push(ctx, jsval_string(jsstr_undefined()));
-        exprval_release(&exprval);
-        return hres;
-    }
+    if(exprval.type == EXPRVAL_INVALID)
+        return stack_push(ctx, jsval_string(jsstr_undefined()));
 
     hres = exprval_to_value(ctx, &exprval, &v);
 
     hres = exprval_to_value(ctx, &exprval, &v);
-    exprval_release(&exprval);
     if(FAILED(hres))
         return hres;
 
     if(FAILED(hres))
         return hres;
 
@@ -1774,28 +2003,26 @@ static HRESULT interp_tonum(script_ctx_t *ctx)
 static HRESULT interp_postinc(script_ctx_t *ctx)
 {
     const int arg = get_op_int(ctx, 0);
 static HRESULT interp_postinc(script_ctx_t *ctx)
 {
     const int arg = get_op_int(ctx, 0);
-    IDispatch *obj;
-    DISPID id;
+    exprval_t ref;
     jsval_t v;
     HRESULT hres;
 
     TRACE("%d\n", arg);
 
     jsval_t v;
     HRESULT hres;
 
     TRACE("%d\n", arg);
 
-    obj = stack_pop_objid(ctx, &id);
-    if(!obj)
+    if(!stack_pop_exprval(ctx, &ref))
         return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
 
         return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
 
-    hres = disp_propget(ctx, obj, id, &v);
+    hres = exprval_propget(ctx, &ref, &v);
     if(SUCCEEDED(hres)) {
         double n;
 
         hres = to_number(ctx, v, &n);
         if(SUCCEEDED(hres))
     if(SUCCEEDED(hres)) {
         double n;
 
         hres = to_number(ctx, v, &n);
         if(SUCCEEDED(hres))
-            hres = disp_propput(ctx, obj, id, jsval_number(n+(double)arg));
+            hres = exprval_propput(ctx, &ref, jsval_number(n+(double)arg));
         if(FAILED(hres))
             jsval_release(v);
     }
         if(FAILED(hres))
             jsval_release(v);
     }
-    IDispatch_Release(obj);
+    exprval_release(&ref);
     if(FAILED(hres))
         return hres;
 
     if(FAILED(hres))
         return hres;
 
@@ -1806,19 +2033,17 @@ static HRESULT interp_postinc(script_ctx_t *ctx)
 static HRESULT interp_preinc(script_ctx_t *ctx)
 {
     const int arg = get_op_int(ctx, 0);
 static HRESULT interp_preinc(script_ctx_t *ctx)
 {
     const int arg = get_op_int(ctx, 0);
-    IDispatch *obj;
+    exprval_t ref;
     double ret;
     double ret;
-    DISPID id;
     jsval_t v;
     HRESULT hres;
 
     TRACE("%d\n", arg);
 
     jsval_t v;
     HRESULT hres;
 
     TRACE("%d\n", arg);
 
-    obj = stack_pop_objid(ctx, &id);
-    if(!obj)
+    if(!stack_pop_exprval(ctx, &ref))
         return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
 
         return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
 
-    hres = disp_propget(ctx, obj, id, &v);
+    hres = exprval_propget(ctx, &ref, &v);
     if(SUCCEEDED(hres)) {
         double n;
 
     if(SUCCEEDED(hres)) {
         double n;
 
@@ -1826,10 +2051,10 @@ static HRESULT interp_preinc(script_ctx_t *ctx)
         jsval_release(v);
         if(SUCCEEDED(hres)) {
             ret = n+(double)arg;
         jsval_release(v);
         if(SUCCEEDED(hres)) {
             ret = n+(double)arg;
-            hres = disp_propput(ctx, obj, id, jsval_number(ret));
+            hres = exprval_propput(ctx, &ref, jsval_number(ret));
         }
     }
         }
     }
-    IDispatch_Release(obj);
+    exprval_release(&ref);
     if(FAILED(hres))
         return hres;
 
     if(FAILED(hres))
         return hres;
 
@@ -2212,8 +2437,7 @@ static HRESULT interp_rshift2(script_ctx_t *ctx)
 /* ECMA-262 3rd Edition    11.13.1 */
 static HRESULT interp_assign(script_ctx_t *ctx)
 {
 /* ECMA-262 3rd Edition    11.13.1 */
 static HRESULT interp_assign(script_ctx_t *ctx)
 {
-    IDispatch *disp;
-    DISPID id;
+    exprval_t ref;
     jsval_t v;
     HRESULT hres;
 
     jsval_t v;
     HRESULT hres;
 
@@ -2221,14 +2445,13 @@ static HRESULT interp_assign(script_ctx_t *ctx)
 
     v = stack_pop(ctx);
 
 
     v = stack_pop(ctx);
 
-    disp = stack_pop_objid(ctx, &id);
-    if(!disp) {
+    if(!stack_pop_exprval(ctx, &ref)) {
         jsval_release(v);
         return throw_reference_error(ctx, JS_E_ILLEGAL_ASSIGN, NULL);
     }
 
         jsval_release(v);
         return throw_reference_error(ctx, JS_E_ILLEGAL_ASSIGN, NULL);
     }
 
-    hres = disp_propput(ctx, disp, id, v);
-    IDispatch_Release(disp);
+    hres = exprval_propput(ctx, &ref, v);
+    exprval_release(&ref);
     if(FAILED(hres)) {
         jsval_release(v);
         return hres;
     if(FAILED(hres)) {
         jsval_release(v);
         return hres;
@@ -2241,18 +2464,16 @@ static HRESULT interp_assign(script_ctx_t *ctx)
 static HRESULT interp_assign_call(script_ctx_t *ctx)
 {
     const unsigned argc = get_op_uint(ctx, 0);
 static HRESULT interp_assign_call(script_ctx_t *ctx)
 {
     const unsigned argc = get_op_uint(ctx, 0);
-    IDispatch *disp;
+    exprval_t ref;
     jsval_t v;
     jsval_t v;
-    DISPID id;
     HRESULT hres;
 
     TRACE("%u\n", argc);
 
     HRESULT hres;
 
     TRACE("%u\n", argc);
 
-    disp = stack_topn_objid(ctx, argc+1, &id);
-    if(!disp)
+    if(!stack_topn_exprval(ctx, argc+1, &ref))
         return throw_reference_error(ctx, JS_E_ILLEGAL_ASSIGN, NULL);
 
         return throw_reference_error(ctx, JS_E_ILLEGAL_ASSIGN, NULL);
 
-    hres = disp_call(ctx, disp, id, DISPATCH_PROPERTYPUT, argc+1, stack_args(ctx, argc+1), NULL);
+    hres = exprval_call(ctx, &ref, DISPATCH_PROPERTYPUT, argc+1, stack_args(ctx, argc+1), NULL);
     if(FAILED(hres))
         return hres;
 
     if(FAILED(hres))
         return hres;
 
@@ -2368,23 +2589,38 @@ OP_LIST
 #undef X
 };
 
 #undef X
 };
 
-static void release_call_frame(call_frame_t *frame)
+static void pop_call_frame(script_ctx_t *ctx)
 {
 {
-    if(frame->arguments_obj) {
-        /* Reset arguments value to cut the reference cycle. Note that since all activation contexts have
-         * their own arguments property, it's impossible to use prototype's one during name lookup */
-        static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0};
-        jsdisp_propput_name(frame->variable_obj, argumentsW, jsval_undefined());
-        jsdisp_release(frame->arguments_obj);
+    call_frame_t *frame = ctx->call_ctx;
+
+    frame->stack_base -= frame->pop_locals + frame->pop_variables;
+
+    assert(frame->scope == frame->base_scope);
+
+    /* If current scope will be kept alive, we need to transfer local variables to its variable object. */
+    if(frame->scope && frame->scope->ref > 1) {
+        HRESULT hres = detach_variable_object(ctx, frame, TRUE);
+        if(FAILED(hres))
+            ERR("Failed to detach variable object: %08x\n", hres);
     }
     }
+
+    if(frame->arguments_obj)
+        detach_arguments_object(frame->arguments_obj);
+    if(frame->scope)
+        scope_release(frame->scope);
+
+    if(frame->pop_variables)
+        stack_popn(ctx, frame->pop_variables);
+    stack_popn(ctx, frame->pop_locals);
+
+    ctx->call_ctx = frame->prev_frame;
+
     if(frame->function_instance)
         jsdisp_release(frame->function_instance);
     if(frame->variable_obj)
         jsdisp_release(frame->variable_obj);
     if(frame->this_obj)
         IDispatch_Release(frame->this_obj);
     if(frame->function_instance)
         jsdisp_release(frame->function_instance);
     if(frame->variable_obj)
         jsdisp_release(frame->variable_obj);
     if(frame->this_obj)
         IDispatch_Release(frame->this_obj);
-    if(frame->scope)
-        scope_release(frame->scope);
     jsval_release(frame->ret);
     release_bytecode(frame->bytecode);
     heap_free(frame);
     jsval_release(frame->ret);
     release_bytecode(frame->bytecode);
     heap_free(frame);
@@ -2406,9 +2642,8 @@ static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres)
 
         stack_popn(ctx, ctx->stack_top-frame->stack_base);
 
 
         stack_popn(ctx, ctx->stack_top-frame->stack_base);
 
-        ctx->call_ctx = frame->prev_frame;
         flags = frame->flags;
         flags = frame->flags;
-        release_call_frame(frame);
+        pop_call_frame(ctx);
         if(!(flags & EXEC_RETURN_TO_INTERP))
             return exception_hres;
     }
         if(!(flags & EXEC_RETURN_TO_INTERP))
             return exception_hres;
     }
@@ -2481,14 +2716,13 @@ static HRESULT enter_bytecode(script_ctx_t *ctx, jsval_t *r)
             assert(ctx->stack_top == frame->stack_base);
             assert(frame->scope == frame->base_scope);
 
             assert(ctx->stack_top == frame->stack_base);
             assert(frame->scope == frame->base_scope);
 
-            ctx->call_ctx = frame->prev_frame;
             if(return_to_interp) {
             if(return_to_interp) {
-                clear_ret(ctx->call_ctx);
-                ctx->call_ctx->ret = steal_ret(frame);
+                clear_ret(frame->prev_frame);
+                frame->prev_frame->ret = steal_ret(frame);
             }else if(r) {
                 *r = steal_ret(frame);
             }
             }else if(r) {
                 *r = steal_ret(frame);
             }
-            release_call_frame(frame);
+            pop_call_frame(ctx);
             if(!return_to_interp)
                 break;
         }else {
             if(!return_to_interp)
                 break;
         }else {
@@ -2512,7 +2746,6 @@ static HRESULT bind_event_target(script_ctx_t *ctx, function_code_t *func, jsdis
         return hres;
 
     hres = exprval_to_value(ctx, &exprval, &v);
         return hres;
 
     hres = exprval_to_value(ctx, &exprval, &v);
-    exprval_release(&exprval);
     if(FAILED(hres))
         return hres;
 
     if(FAILED(hres))
         return hres;
 
@@ -2536,8 +2769,85 @@ static HRESULT bind_event_target(script_ctx_t *ctx, function_code_t *func, jsdis
     return hres;
 }
 
     return hres;
 }
 
+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)
+{
+    const unsigned orig_stack = ctx->stack_top;
+    scope_chain_t *scope;
+    unsigned i;
+    jsval_t v;
+    HRESULT hres;
+
+    /* If arguments are already on the stack, we may use them. */
+    if(argv + argc == ctx->stack + ctx->stack_top) {
+        frame->arguments_off = argv - ctx->stack;
+        i = argc;
+    }else {
+        frame->arguments_off = ctx->stack_top;
+        for(i = 0; i < argc; i++) {
+            hres = jsval_copy(argv[i], &v);
+            if(SUCCEEDED(hres))
+                hres = stack_push(ctx, v);
+            if(FAILED(hres)) {
+                stack_popn(ctx, i);
+                return hres;
+            }
+        }
+    }
+
+    /* If fewer than declared arguments were passed, fill remaining with undefined value. */
+    for(; i < frame->function->param_cnt; i++) {
+        hres = stack_push(ctx, jsval_undefined());
+        if(FAILED(hres)) {
+            stack_popn(ctx, ctx->stack_top - orig_stack);
+            return hres;
+        }
+    }
+
+    frame->pop_locals = ctx->stack_top - orig_stack;
+
+    frame->variables_off = ctx->stack_top;
+
+    for(i = 0; i < frame->function->var_cnt; i++) {
+        hres = stack_push(ctx, jsval_undefined());
+        if(FAILED(hres)) {
+            stack_popn(ctx, ctx->stack_top - orig_stack);
+            return hres;
+        }
+    }
+
+    frame->pop_variables = i;
+
+    hres = scope_push(scope_chain, variable_object, to_disp(variable_object), &scope);
+    if(FAILED(hres)) {
+        stack_popn(ctx, ctx->stack_top - orig_stack);
+        return hres;
+    }
+
+    for(i = 0; i < frame->function->func_cnt; i++) {
+        if(frame->function->funcs[i].name && !frame->function->funcs[i].event_target) {
+            jsdisp_t *func_obj;
+            unsigned off;
+
+            hres = create_source_function(ctx, frame->bytecode, frame->function->funcs+i, scope, &func_obj);
+            if(FAILED(hres)) {
+                stack_popn(ctx, ctx->stack_top - orig_stack);
+                scope_release(scope);
+                return hres;
+            }
+
+            off = local_off(frame, frame->function->funcs[i].local_ref);
+            jsval_release(ctx->stack[off]);
+            ctx->stack[off] = jsval_obj(func_obj);
+        }
+    }
+
+    scope->frame = frame;
+    frame->base_scope = frame->scope = scope;
+    return S_OK;
+}
+
 HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, function_code_t *function, scope_chain_t *scope,
 HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, function_code_t *function, scope_chain_t *scope,
-        IDispatch *this_obj, jsdisp_t *function_instance, jsdisp_t *variable_obj, jsdisp_t *arguments_obj, jsval_t *r)
+        IDispatch *this_obj, jsdisp_t *function_instance, jsdisp_t *variable_obj, unsigned argc, jsval_t *argv, jsval_t *r)
 {
     call_frame_t *frame;
     unsigned i;
 {
     call_frame_t *frame;
     unsigned i;
@@ -2546,29 +2856,38 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi
     for(i = 0; i < function->func_cnt; i++) {
         jsdisp_t *func_obj;
 
     for(i = 0; i < function->func_cnt; i++) {
         jsdisp_t *func_obj;
 
-        if(!function->funcs[i].name)
+        if(!function->funcs[i].event_target)
             continue;
 
         hres = create_source_function(ctx, bytecode, function->funcs+i, scope, &func_obj);
         if(FAILED(hres))
             return hres;
 
             continue;
 
         hres = create_source_function(ctx, bytecode, function->funcs+i, scope, &func_obj);
         if(FAILED(hres))
             return hres;
 
-        if(function->funcs[i].event_target)
-            hres = bind_event_target(ctx, function->funcs+i, func_obj);
-        else
-            hres = jsdisp_propput_name(variable_obj, function->funcs[i].name, jsval_obj(func_obj));
+        hres = bind_event_target(ctx, function->funcs+i, func_obj);
         jsdisp_release(func_obj);
         if(FAILED(hres))
             return hres;
     }
 
         jsdisp_release(func_obj);
         if(FAILED(hres))
             return hres;
     }
 
-    for(i=0; i < function->var_cnt; i++) {
-        if(!(flags & EXEC_GLOBAL) || !lookup_global_members(ctx, function->variables[i], NULL)) {
-            DISPID id = 0;
+    if(flags & (EXEC_GLOBAL | EXEC_EVAL)) {
+        for(i=0; i < function->var_cnt; i++) {
+            TRACE("[%d] %s %d\n", i, debugstr_w(function->variables[i].name), function->variables[i].func_id);
+            if(function->variables[i].func_id != -1) {
+                jsdisp_t *func_obj;
 
 
-            hres = jsdisp_get_id(variable_obj, function->variables[i], fdexNameEnsure, &id);
-            if(FAILED(hres))
-                return hres;
+                hres = create_source_function(ctx, bytecode, function->funcs+function->variables[i].func_id, scope, &func_obj);
+                if(FAILED(hres))
+                    return hres;
+
+                hres = jsdisp_propput_name(variable_obj, function->variables[i].name, jsval_obj(func_obj));
+                jsdisp_release(func_obj);
+            }else if(!(flags & EXEC_GLOBAL) || !lookup_global_members(ctx, function->variables[i].name, NULL)) {
+                DISPID id = 0;
+
+                hres = jsdisp_get_id(variable_obj, function->variables[i].name, fdexNameEnsure, &id);
+                if(FAILED(hres))
+                    return hres;
+            }
         }
     }
 
         }
     }
 
@@ -2576,7 +2895,7 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi
     if(this_obj) {
         jsdisp_t *jsthis;
 
     if(this_obj) {
         jsdisp_t *jsthis;
 
-        jsthis = iface_to_jsdisp((IUnknown*)this_obj);
+        jsthis = iface_to_jsdisp(this_obj);
         if(jsthis) {
             if(jsthis->builtin_info->class == JSCLASS_GLOBAL || jsthis->builtin_info->class == JSCLASS_NONE)
                 this_obj = NULL;
         if(jsthis) {
             if(jsthis->builtin_info->class == JSCLASS_GLOBAL || jsthis->builtin_info->class == JSCLASS_NONE)
                 this_obj = NULL;
@@ -2584,18 +2903,34 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi
         }
     }
 
         }
     }
 
+    if(ctx->call_ctx && (flags & EXEC_EVAL)) {
+        hres = detach_variable_object(ctx, ctx->call_ctx, FALSE);
+        if(FAILED(hres))
+            return hres;
+    }
+
     frame = heap_alloc_zero(sizeof(*frame));
     if(!frame)
         return E_OUTOFMEMORY;
 
     frame = heap_alloc_zero(sizeof(*frame));
     if(!frame)
         return E_OUTOFMEMORY;
 
-    frame->bytecode = bytecode_addref(bytecode);
     frame->function = function;
     frame->function = function;
-    frame->ip = function->instr_off;
-    frame->stack_base = ctx->stack_top;
     frame->ret = jsval_undefined();
     frame->ret = jsval_undefined();
-    if(scope)
+    frame->argc = argc;
+    frame->bytecode = bytecode_addref(bytecode);
+
+    if(!(flags & (EXEC_GLOBAL|EXEC_EVAL))) {
+        hres = setup_scope(ctx, frame, scope, variable_obj, argc, argv);
+        if(FAILED(hres)) {
+            release_bytecode(frame->bytecode);
+            heap_free(frame);
+            return hres;
+        }
+    }else if(scope) {
         frame->base_scope = frame->scope = scope_addref(scope);
         frame->base_scope = frame->scope = scope_addref(scope);
+    }
 
 
+    frame->ip = function->instr_off;
+    frame->stack_base = ctx->stack_top;
     if(this_obj)
         frame->this_obj = this_obj;
     else if(ctx->host_global)
     if(this_obj)
         frame->this_obj = this_obj;
     else if(ctx->host_global)
@@ -2606,8 +2941,6 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi
 
     if(function_instance)
         frame->function_instance = jsdisp_addref(function_instance);
 
     if(function_instance)
         frame->function_instance = jsdisp_addref(function_instance);
-    if(arguments_obj)
-        frame->arguments_obj = jsdisp_addref(arguments_obj);
 
     frame->flags = flags;
     frame->variable_obj = jsdisp_addref(variable_obj);
 
     frame->flags = flags;
     frame->variable_obj = jsdisp_addref(variable_obj);
index 686e995..18833ec 100644 (file)
@@ -50,6 +50,8 @@
     X(int,        1, ARG_INT,    0)        \
     X(jmp,        0, ARG_ADDR,   0)        \
     X(jmp_z,      0, ARG_ADDR,   0)        \
     X(int,        1, ARG_INT,    0)        \
     X(jmp,        0, ARG_ADDR,   0)        \
     X(jmp_z,      0, ARG_ADDR,   0)        \
+    X(local,      1, ARG_INT,    0)        \
+    X(local_ref,  1, ARG_INT,    ARG_UINT) \
     X(lshift,     1, 0,0)                  \
     X(lt,         1, 0,0)                  \
     X(lteq,       1, 0,0)                  \
     X(lshift,     1, 0,0)                  \
     X(lt,         1, 0,0)                  \
     X(lteq,       1, 0,0)                  \
@@ -91,7 +93,6 @@
     X(setret,     1, 0,0)                  \
     X(sub,        1, 0,0)                  \
     X(undefined,  1, 0,0)                  \
     X(setret,     1, 0,0)                  \
     X(sub,        1, 0,0)                  \
     X(undefined,  1, 0,0)                  \
-    X(var_set,    1, ARG_BSTR,   0)        \
     X(void,       1, 0,0)                  \
     X(xor,        1, 0,0)
 
     X(void,       1, 0,0)                  \
     X(xor,        1, 0,0)
 
@@ -128,8 +129,14 @@ typedef struct {
     } u;
 } instr_t;
 
     } u;
 } instr_t;
 
+typedef struct {
+    BSTR name;
+    int ref;
+} local_ref_t;
+
 typedef struct _function_code_t {
     BSTR name;
 typedef struct _function_code_t {
     BSTR name;
+    int local_ref;
     BSTR event_target;
     unsigned instr_off;
 
     BSTR event_target;
     unsigned instr_off;
 
@@ -140,12 +147,20 @@ typedef struct _function_code_t {
     struct _function_code_t *funcs;
 
     unsigned var_cnt;
     struct _function_code_t *funcs;
 
     unsigned var_cnt;
-    BSTR *variables;
+    struct {
+        BSTR name;
+        int func_id; /* -1 if not a function */
+    } *variables;
 
     unsigned param_cnt;
     BSTR *params;
 
     unsigned param_cnt;
     BSTR *params;
+
+    unsigned locals_cnt;
+    local_ref_t *locals;
 } function_code_t;
 
 } function_code_t;
 
+local_ref_t *lookup_local(const function_code_t*,const WCHAR*) DECLSPEC_HIDDEN;
+
 typedef struct _bytecode_t {
     LONG ref;
 
 typedef struct _bytecode_t {
     LONG ref;
 
@@ -180,6 +195,7 @@ typedef struct _scope_chain_t {
     LONG ref;
     jsdisp_t *jsobj;
     IDispatch *obj;
     LONG ref;
     jsdisp_t *jsobj;
     IDispatch *obj;
+    struct _call_frame_t *frame;
     struct _scope_chain_t *next;
 } scope_chain_t;
 
     struct _scope_chain_t *next;
 } scope_chain_t;
 
@@ -210,6 +226,12 @@ typedef struct _call_frame_t {
     jsdisp_t *arguments_obj;
     DWORD flags;
 
     jsdisp_t *arguments_obj;
     DWORD flags;
 
+    unsigned argc;
+    unsigned pop_locals;
+    unsigned arguments_off;
+    unsigned variables_off;
+    unsigned pop_variables;
+
     bytecode_t *bytecode;
     function_code_t *function;
 
     bytecode_t *bytecode;
     function_code_t *function;
 
@@ -219,8 +241,11 @@ typedef struct _call_frame_t {
 #define EXEC_GLOBAL            0x0001
 #define EXEC_CONSTRUCTOR       0x0002
 #define EXEC_RETURN_TO_INTERP  0x0004
 #define EXEC_GLOBAL            0x0001
 #define EXEC_CONSTRUCTOR       0x0002
 #define EXEC_RETURN_TO_INTERP  0x0004
+#define EXEC_EVAL              0x0008
 
 HRESULT exec_source(script_ctx_t*,DWORD,bytecode_t*,function_code_t*,scope_chain_t*,IDispatch*,
 
 HRESULT exec_source(script_ctx_t*,DWORD,bytecode_t*,function_code_t*,scope_chain_t*,IDispatch*,
-        jsdisp_t*,jsdisp_t*,jsdisp_t*,jsval_t*) DECLSPEC_HIDDEN;
+        jsdisp_t*,jsdisp_t*,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
 
 HRESULT create_source_function(script_ctx_t*,bytecode_t*,function_code_t*,scope_chain_t*,jsdisp_t**) DECLSPEC_HIDDEN;
 
 HRESULT create_source_function(script_ctx_t*,bytecode_t*,function_code_t*,scope_chain_t*,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT setup_arguments_object(script_ctx_t*,call_frame_t*) DECLSPEC_HIDDEN;
+void detach_arguments_object(jsdisp_t*) DECLSPEC_HIDDEN;
index 4319721..aca6e26 100644 (file)
@@ -32,7 +32,9 @@ typedef struct {
 typedef struct {
     jsdisp_t jsdisp;
     FunctionInstance *function;
 typedef struct {
     jsdisp_t jsdisp;
     FunctionInstance *function;
-    jsdisp_t *var_obj;
+    jsval_t *buf;
+    call_frame_t *frame;
+    unsigned argc;
 } ArgumentsInstance;
 
 static inline FunctionInstance *function_from_jsdisp(jsdisp_t *jsdisp)
 } ArgumentsInstance;
 
 static inline FunctionInstance *function_from_jsdisp(jsdisp_t *jsdisp)
@@ -50,6 +52,11 @@ static inline FunctionInstance *function_this(vdisp_t *jsthis)
     return is_vclass(jsthis, JSCLASS_FUNCTION) ? function_from_vdisp(jsthis) : NULL;
 }
 
     return is_vclass(jsthis, JSCLASS_FUNCTION) ? function_from_vdisp(jsthis) : NULL;
 }
 
+static inline ArgumentsInstance *arguments_from_jsdisp(jsdisp_t *jsdisp)
+{
+    return CONTAINING_RECORD(jsdisp, ArgumentsInstance, jsdisp);
+}
+
 static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0};
 
 static const WCHAR lengthW[] = {'l','e','n','g','t','h',0};
 static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0};
 
 static const WCHAR lengthW[] = {'l','e','n','g','t','h',0};
@@ -58,21 +65,6 @@ static const WCHAR applyW[] = {'a','p','p','l','y',0};
 static const WCHAR callW[] = {'c','a','l','l',0};
 static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0};
 
 static const WCHAR callW[] = {'c','a','l','l',0};
 static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0};
 
-static HRESULT init_parameters(jsdisp_t *var_disp, FunctionInstance *function, unsigned argc, jsval_t *argv)
-{
-    DWORD i=0;
-    HRESULT hres;
-
-    for(i=0; i < function->func_code->param_cnt; i++) {
-        hres = jsdisp_propput_name(var_disp, function->func_code->params[i],
-                i < argc ? argv[i] : jsval_undefined());
-        if(FAILED(hres))
-            return hres;
-    }
-
-    return S_OK;
-}
-
 static HRESULT Arguments_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
         jsval_t *r)
 {
 static HRESULT Arguments_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
         jsval_t *r)
 {
@@ -84,35 +76,69 @@ static void Arguments_destructor(jsdisp_t *jsdisp)
 {
     ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
 
 {
     ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
 
+    TRACE("(%p)\n", arguments);
+
+    if(arguments->buf) {
+        unsigned i;
+        for(i = 0; i < arguments->argc; i++)
+            jsval_release(arguments->buf[i]);
+        heap_free(arguments->buf);
+    }
+
     jsdisp_release(&arguments->function->dispex);
     jsdisp_release(&arguments->function->dispex);
-    jsdisp_release(arguments->var_obj);
     heap_free(arguments);
 }
 
 static unsigned Arguments_idx_length(jsdisp_t *jsdisp)
 {
     ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
     heap_free(arguments);
 }
 
 static unsigned Arguments_idx_length(jsdisp_t *jsdisp)
 {
     ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
-    return arguments->function->length;
+    return arguments->argc;
+}
+
+static jsval_t *get_argument_ref(ArgumentsInstance *arguments, unsigned idx)
+{
+    if(arguments->buf)
+        return arguments->buf + idx;
+    if(arguments->frame->base_scope->frame || idx >= arguments->frame->function->param_cnt)
+        return arguments->jsdisp.ctx->stack + arguments->frame->arguments_off + idx;
+    return NULL;
 }
 
 }
 
-static HRESULT Arguments_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *res)
+static HRESULT Arguments_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r)
 {
     ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
 {
     ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
+    jsval_t *ref;
 
     TRACE("%p[%u]\n", arguments, idx);
 
 
     TRACE("%p[%u]\n", arguments, idx);
 
+    if((ref = get_argument_ref(arguments, idx)))
+        return jsval_copy(*ref, r);
+
     /* FIXME: Accessing by name won't work for duplicated argument names */
     /* FIXME: Accessing by name won't work for duplicated argument names */
-    return jsdisp_propget_name(arguments->var_obj, arguments->function->func_code->params[idx], res);
+    return jsdisp_propget_name(arguments->frame->base_scope->jsobj, arguments->function->func_code->params[idx], r);
 }
 
 static HRESULT Arguments_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val)
 {
     ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
 }
 
 static HRESULT Arguments_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val)
 {
     ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
+    jsval_t *ref;
+    HRESULT hres;
 
     TRACE("%p[%u] = %s\n", arguments, idx, debugstr_jsval(val));
 
 
     TRACE("%p[%u] = %s\n", arguments, idx, debugstr_jsval(val));
 
+    if((ref = get_argument_ref(arguments, idx))) {
+        jsval_t copy;
+        hres = jsval_copy(val, &copy);
+        if(FAILED(hres))
+            return hres;
+
+        jsval_release(*ref);
+        *ref = copy;
+        return S_OK;
+    }
+
     /* FIXME: Accessing by name won't work for duplicated argument names */
     /* FIXME: Accessing by name won't work for duplicated argument names */
-    return jsdisp_propput_name(arguments->var_obj, arguments->function->func_code->params[idx], val);
+    return jsdisp_propput_name(arguments->frame->base_scope->jsobj, arguments->function->func_code->params[idx], val);
 }
 
 static const builtin_info_t Arguments_info = {
 }
 
 static const builtin_info_t Arguments_info = {
@@ -126,11 +152,9 @@ static const builtin_info_t Arguments_info = {
     Arguments_idx_put
 };
 
     Arguments_idx_put
 };
 
-static HRESULT create_arguments(script_ctx_t *ctx, FunctionInstance *calee, jsdisp_t *var_obj,
-        unsigned argc, jsval_t *argv, jsdisp_t **ret)
+HRESULT setup_arguments_object(script_ctx_t *ctx, call_frame_t *frame)
 {
     ArgumentsInstance *args;
 {
     ArgumentsInstance *args;
-    unsigned i;
     HRESULT hres;
 
     static const WCHAR caleeW[] = {'c','a','l','l','e','e',0};
     HRESULT hres;
 
     static const WCHAR caleeW[] = {'c','a','l','l','e','e',0};
@@ -145,60 +169,64 @@ static HRESULT create_arguments(script_ctx_t *ctx, FunctionInstance *calee, jsdi
         return hres;
     }
 
         return hres;
     }
 
-    jsdisp_addref(&calee->dispex);
-    args->function = calee;
-    args->var_obj = jsdisp_addref(var_obj);
+    args->function = function_from_jsdisp(jsdisp_addref(frame->function_instance));
+    args->argc = frame->argc;
+    args->frame = frame;
 
 
-    /* Store unnamed arguments directly in arguments object */
-    for(i = calee->length; i < argc; i++) {
-        WCHAR buf[12];
-
-        static const WCHAR formatW[] = {'%','d',0};
-
-        sprintfW(buf, formatW, i);
-        hres = jsdisp_propput_dontenum(&args->jsdisp, buf, argv[i]);
-        if(FAILED(hres))
-            break;
-    }
-
-    if(SUCCEEDED(hres)) {
-        hres = jsdisp_propput_dontenum(&args->jsdisp, lengthW, jsval_number(argc));
-        if(SUCCEEDED(hres))
-            hres = jsdisp_propput_dontenum(&args->jsdisp, caleeW, jsval_disp(to_disp(&calee->dispex)));
-    }
+    hres = jsdisp_propput_dontenum(&args->jsdisp, lengthW, jsval_number(args->argc));
+    if(SUCCEEDED(hres))
+        hres = jsdisp_propput_dontenum(&args->jsdisp, caleeW, jsval_disp(to_disp(&args->function->dispex)));
+    if(SUCCEEDED(hres))
+        hres = jsdisp_propput(frame->base_scope->jsobj, argumentsW, PROPF_DONTDELETE, jsval_obj(&args->jsdisp));
     if(FAILED(hres)) {
         jsdisp_release(&args->jsdisp);
         return hres;
     }
 
     if(FAILED(hres)) {
         jsdisp_release(&args->jsdisp);
         return hres;
     }
 
-    *ret = &args->jsdisp;
+    frame->arguments_obj = &args->jsdisp;
     return S_OK;
 }
 
     return S_OK;
 }
 
-static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, unsigned argc, jsval_t *argv, jsdisp_t **ret)
+void detach_arguments_object(jsdisp_t *args_disp)
 {
 {
-    jsdisp_t *var_disp;
+    ArgumentsInstance *arguments = arguments_from_jsdisp(args_disp);
+    call_frame_t *frame = arguments->frame;
+    const BOOL on_stack = frame->base_scope->frame == frame;
     HRESULT hres;
 
     HRESULT hres;
 
-    hres = create_dispex(ctx, NULL, NULL, &var_disp);
-    if(FAILED(hres))
-        return hres;
-
-    hres = init_parameters(var_disp, function, argc, argv);
-    if(FAILED(hres)) {
-        jsdisp_release(var_disp);
-        return hres;
+    /* Reset arguments value to cut the reference cycle. Note that since all activation contexts have
+     * their own arguments property, it's impossible to use prototype's one during name lookup */
+    jsdisp_propput_name(frame->base_scope->jsobj, argumentsW, jsval_undefined());
+    arguments->frame = NULL;
+
+    /* Don't bother coppying arguments if call frame holds the last reference. */
+    if(arguments->jsdisp.ref > 1) {
+        arguments->buf = heap_alloc(arguments->argc * sizeof(*arguments->buf));
+        if(arguments->buf) {
+            int i;
+
+            for(i = 0; i < arguments->argc ; i++) {
+                if(on_stack || i >= frame->function->param_cnt)
+                    hres = jsval_copy(arguments->jsdisp.ctx->stack[frame->arguments_off + i], arguments->buf+i);
+                else
+                    hres = jsdisp_propget_name(frame->base_scope->jsobj, frame->function->params[i], arguments->buf+i);
+                if(FAILED(hres))
+                    arguments->buf[i] = jsval_undefined();
+            }
+        }else {
+            ERR("out of memory\n");
+            arguments->argc = 0;
+        }
     }
 
     }
 
-    *ret = var_disp;
-    return S_OK;
+    jsdisp_release(frame->arguments_obj);
 }
 
 static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj, unsigned argc, jsval_t *argv,
         BOOL is_constructor, BOOL caller_execs_source, jsval_t *r)
 {
 }
 
 static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj, unsigned argc, jsval_t *argv,
         BOOL is_constructor, BOOL caller_execs_source, jsval_t *r)
 {
-    jsdisp_t *var_disp, *arg_disp;
-    scope_chain_t *scope;
+    jsdisp_t *var_disp;
+    DWORD exec_flags = 0;
     HRESULT hres;
 
     if(ctx->state == SCRIPTSTATE_UNINITIALIZED || ctx->state == SCRIPTSTATE_CLOSED) {
     HRESULT hres;
 
     if(ctx->state == SCRIPTSTATE_UNINITIALIZED || ctx->state == SCRIPTSTATE_CLOSED) {
@@ -211,38 +239,17 @@ static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDis
         return E_FAIL;
     }
 
         return E_FAIL;
     }
 
-    hres = create_var_disp(ctx, function, argc, argv, &var_disp);
+    hres = create_dispex(ctx, NULL, NULL, &var_disp);
     if(FAILED(hres))
         return hres;
 
     if(FAILED(hres))
         return hres;
 
-    hres = create_arguments(ctx, function, var_disp, argc, argv, &arg_disp);
-    if(FAILED(hres)) {
-        jsdisp_release(var_disp);
-        return hres;
-    }
+    if(caller_execs_source)
+        exec_flags |= EXEC_RETURN_TO_INTERP;
+    if(is_constructor)
+        exec_flags |= EXEC_CONSTRUCTOR;
+    hres = exec_source(ctx, exec_flags, function->code, function->func_code, function->scope_chain, this_obj,
+            &function->dispex, var_disp, argc, argv, r);
 
 
-    hres = jsdisp_propput(var_disp, argumentsW, PROPF_DONTDELETE, jsval_obj(arg_disp));
-    if(FAILED(hres)) {
-        jsdisp_release(arg_disp);
-        jsdisp_release(var_disp);
-        return hres;
-    }
-
-    hres = scope_push(function->scope_chain, var_disp, to_disp(var_disp), &scope);
-    if(SUCCEEDED(hres)) {
-        DWORD exec_flags = 0;
-
-        if(caller_execs_source)
-            exec_flags |= EXEC_RETURN_TO_INTERP;
-        if(is_constructor)
-            exec_flags |= EXEC_CONSTRUCTOR;
-        hres = exec_source(ctx, exec_flags, function->code, function->func_code, scope, this_obj,
-                &function->dispex, var_disp, arg_disp, r);
-
-        scope_release(scope);
-    }
-
-    jsdisp_release(arg_disp);
     jsdisp_release(var_disp);
     return hres;
 }
     jsdisp_release(var_disp);
     return hres;
 }
@@ -419,7 +426,7 @@ static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un
 
     TRACE("\n");
 
 
     TRACE("\n");
 
-    if(!(function = function_this(jsthis)))
+    if(!(function = function_this(jsthis)) && (jsthis->flags & VDISP_JSDISP))
         return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
 
     if(argc) {
         return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
 
     if(argc) {
@@ -434,7 +441,7 @@ static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un
         jsdisp_t *arg_array = NULL;
 
         if(is_object_instance(argv[1])) {
         jsdisp_t *arg_array = NULL;
 
         if(is_object_instance(argv[1])) {
-            arg_array = iface_to_jsdisp((IUnknown*)get_object(argv[1]));
+            arg_array = iface_to_jsdisp(get_object(argv[1]));
             if(arg_array &&
                (!is_class(arg_array, JSCLASS_ARRAY) && !is_class(arg_array, JSCLASS_ARGUMENTS) )) {
                 jsdisp_release(arg_array);
             if(arg_array &&
                (!is_class(arg_array, JSCLASS_ARRAY) && !is_class(arg_array, JSCLASS_ARGUMENTS) )) {
                 jsdisp_release(arg_array);
@@ -451,8 +458,20 @@ static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un
         }
     }
 
         }
     }
 
-    if(SUCCEEDED(hres))
-        hres = call_function(ctx, function, this_obj, cnt, args, (flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE) != 0, r);
+    if(SUCCEEDED(hres)) {
+        if(function) {
+            hres = call_function(ctx, function, this_obj, cnt, args, (flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE) != 0, r);
+        }else {
+            jsval_t res;
+            hres = disp_call_value(ctx, jsthis->u.disp, this_obj, DISPATCH_METHOD, cnt, args, &res);
+            if(SUCCEEDED(hres)) {
+                if(r)
+                    *r = res;
+                else
+                    jsval_release(res);
+            }
+        }
+    }
 
     if(this_obj)
         IDispatch_Release(this_obj);
 
     if(this_obj)
         IDispatch_Release(this_obj);
@@ -529,11 +548,17 @@ static HRESULT Function_get_arguments(script_ctx_t *ctx, jsdisp_t *jsthis, jsval
 {
     FunctionInstance *function = function_from_jsdisp(jsthis);
     call_frame_t *frame;
 {
     FunctionInstance *function = function_from_jsdisp(jsthis);
     call_frame_t *frame;
+    HRESULT hres;
 
     TRACE("\n");
 
     for(frame = ctx->call_ctx; frame; frame = frame->prev_frame) {
         if(frame->function_instance == &function->dispex) {
 
     TRACE("\n");
 
     for(frame = ctx->call_ctx; frame; frame = frame->prev_frame) {
         if(frame->function_instance == &function->dispex) {
+            if(!frame->arguments_obj) {
+                hres = setup_arguments_object(ctx, frame);
+                if(FAILED(hres))
+                    return hres;
+            }
             *r = jsval_obj(jsdisp_addref(frame->arguments_obj));
             return S_OK;
         }
             *r = jsval_obj(jsdisp_addref(frame->arguments_obj));
             return S_OK;
         }
@@ -775,7 +800,7 @@ static HRESULT construct_function(script_ctx_t *ctx, unsigned argc, jsval_t *arg
     if(FAILED(hres))
         return hres;
 
     if(FAILED(hres))
         return hres;
 
-    if(code->global_code.func_cnt != 1 || code->global_code.var_cnt) {
+    if(code->global_code.func_cnt != 1 || code->global_code.var_cnt != 1) {
         ERR("Invalid parser result!\n");
         release_bytecode(code);
         return E_UNEXPECTED;
         ERR("Invalid parser result!\n");
         release_bytecode(code);
         return E_UNEXPECTED;
index 6348a7b..ac8a15f 100644 (file)
@@ -179,7 +179,7 @@ HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned a
         jsval_t *r)
 {
     call_frame_t *frame;
         jsval_t *r)
 {
     call_frame_t *frame;
-    DWORD exec_flags = 0;
+    DWORD exec_flags = EXEC_EVAL;
     bytecode_t *code;
     const WCHAR *src;
     HRESULT hres;
     bytecode_t *code;
     const WCHAR *src;
     HRESULT hres;
@@ -219,7 +219,7 @@ HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned a
     if(flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE)
         exec_flags |= EXEC_RETURN_TO_INTERP;
     hres = exec_source(ctx, exec_flags, code, &code->global_code, frame->scope,
     if(flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE)
         exec_flags |= EXEC_RETURN_TO_INTERP;
     hres = exec_source(ctx, exec_flags, code, &code->global_code, frame->scope,
-            frame->this_obj, NULL, frame->variable_obj, NULL, r);
+            frame->this_obj, NULL, frame->variable_obj, 0, NULL, r);
     release_bytecode(code);
     return hres;
 }
     release_bytecode(code);
     return hres;
 }
index 3755448..9e8b3cb 100644 (file)
@@ -99,7 +99,7 @@ static HRESULT exec_global_code(JScript *This, bytecode_t *code)
     IActiveScriptSite_OnEnterScript(This->site);
 
     clear_ei(This->ctx);
     IActiveScriptSite_OnEnterScript(This->site);
 
     clear_ei(This->ctx);
-    hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, This->ctx->global, NULL, NULL);
+    hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, This->ctx->global, 0, NULL, NULL);
 
     IActiveScriptSite_OnLeaveScript(This->site);
     return hres;
 
     IActiveScriptSite_OnLeaveScript(This->site);
     return hres;
@@ -765,7 +765,7 @@ static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface,
         IActiveScriptSite_OnEnterScript(This->site);
 
         clear_ei(This->ctx);
         IActiveScriptSite_OnEnterScript(This->site);
 
         clear_ei(This->ctx);
-        hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, This->ctx->global, NULL, &r);
+        hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, This->ctx->global, 0, NULL, &r);
         if(SUCCEEDED(hres)) {
             if(pvarResult)
                 hres = jsval_to_variant(r, pvarResult);
         if(SUCCEEDED(hres)) {
             if(pvarResult)
                 hres = jsval_to_variant(r, pvarResult);
index 274238d..d3b3b01 100644 (file)
@@ -142,7 +142,7 @@ typedef enum {
     JSCLASS_JSON
 } jsclass_t;
 
     JSCLASS_JSON
 } jsclass_t;
 
-jsdisp_t *iface_to_jsdisp(IUnknown*) DECLSPEC_HIDDEN;
+jsdisp_t *iface_to_jsdisp(IDispatch*) DECLSPEC_HIDDEN;
 
 typedef struct {
     union {
 
 typedef struct {
     union {
@@ -184,7 +184,7 @@ static inline void set_disp(vdisp_t *vdisp, IDispatch *disp)
     jsdisp_t *jsdisp;
     HRESULT hres;
 
     jsdisp_t *jsdisp;
     HRESULT hres;
 
-    jsdisp = iface_to_jsdisp((IUnknown*)disp);
+    jsdisp = iface_to_jsdisp(disp);
     if(jsdisp) {
         vdisp->u.jsdisp = jsdisp;
         vdisp->flags = VDISP_JSDISP | VDISP_DISPEX;
     if(jsdisp) {
         vdisp->u.jsdisp = jsdisp;
         vdisp->flags = VDISP_JSDISP | VDISP_DISPEX;
index 648a8e6..fd1e471 100644 (file)
@@ -412,7 +412,7 @@ static HRESULT maybe_to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *r)
     jsdisp_t *obj;
     HRESULT hres;
 
     jsdisp_t *obj;
     HRESULT hres;
 
-    if(!is_object_instance(val) || !get_object(val) || !(obj = iface_to_jsdisp((IUnknown*)get_object(val))))
+    if(!is_object_instance(val) || !get_object(val) || !(obj = iface_to_jsdisp(get_object(val))))
         return jsval_copy(val, r);
 
     if(is_class(obj, JSCLASS_NUMBER)) {
         return jsval_copy(val, r);
 
     if(is_class(obj, JSCLASS_NUMBER)) {
@@ -663,7 +663,7 @@ static HRESULT stringify(stringify_ctx_t *ctx, jsval_t val)
         jsdisp_t *obj;
         DISPID id;
 
         jsdisp_t *obj;
         DISPID id;
 
-        obj = iface_to_jsdisp((IUnknown*)get_object(val));
+        obj = iface_to_jsdisp(get_object(val));
         if(!obj)
             return S_FALSE;
 
         if(!obj)
             return S_FALSE;
 
@@ -721,7 +721,7 @@ static HRESULT stringify(stringify_ctx_t *ctx, jsval_t val)
     case JSV_OBJECT: {
         jsdisp_t *obj;
 
     case JSV_OBJECT: {
         jsdisp_t *obj;
 
-        obj = iface_to_jsdisp((IUnknown*)get_object(value));
+        obj = iface_to_jsdisp(get_object(value));
         if(!obj) {
             hres = S_FALSE;
             break;
         if(!obj) {
             hres = S_FALSE;
             break;
index 3eab058..16d19a7 100644 (file)
@@ -328,6 +328,7 @@ static HRESULT RegExp_set_lastIndex(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t
 
     TRACE("\n");
 
 
     TRACE("\n");
 
+    jsval_release(regexp->last_index_val);
     hres = jsval_copy(value, &regexp->last_index_val);
     if(FAILED(hres))
         return hres;
     hres = jsval_copy(value, &regexp->last_index_val);
     if(FAILED(hres))
         return hres;
@@ -697,7 +698,7 @@ HRESULT create_regexp_var(script_ctx_t *ctx, jsval_t src_arg, jsval_t *flags_arg
     if(is_object_instance(src_arg)) {
         jsdisp_t *obj;
 
     if(is_object_instance(src_arg)) {
         jsdisp_t *obj;
 
-        obj = iface_to_jsdisp((IUnknown*)get_object(src_arg));
+        obj = iface_to_jsdisp(get_object(src_arg));
         if(obj) {
             if(is_class(obj, JSCLASS_REGEXP)) {
                 RegExpInstance *regexp = (RegExpInstance*)obj;
         if(obj) {
             if(is_class(obj, JSCLASS_REGEXP)) {
                 RegExpInstance *regexp = (RegExpInstance*)obj;
@@ -948,7 +949,7 @@ static HRESULT RegExpConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags
     case DISPATCH_METHOD:
         if(argc) {
             if(is_object_instance(argv[0])) {
     case DISPATCH_METHOD:
         if(argc) {
             if(is_object_instance(argv[0])) {
-                jsdisp_t *jsdisp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
+                jsdisp_t *jsdisp = iface_to_jsdisp(get_object(argv[0]));
                 if(jsdisp) {
                     if(is_class(jsdisp, JSCLASS_REGEXP)) {
                         if(argc > 1 && !is_undefined(argv[1])) {
                 if(jsdisp) {
                     if(is_class(jsdisp, JSCLASS_REGEXP)) {
                         if(argc > 1 && !is_undefined(argv[1])) {
index 0edb3cf..3fbee0c 100644 (file)
@@ -138,7 +138,7 @@ void heap_pool_clear(heap_pool_t *heap)
     if(!heap)
         return;
 
     if(!heap)
         return;
 
-    while((tmp = list_next(&heap->custom_blocks, &heap->custom_blocks))) {
+    while((tmp = list_head(&heap->custom_blocks))) {
         list_remove(tmp);
         heap_free(tmp);
     }
         list_remove(tmp);
         heap_free(tmp);
     }
@@ -202,13 +202,17 @@ static HRESULT jsval_variant(jsval_t *val, VARIANT *var)
 
     __JSVAL_TYPE(*val) = JSV_VARIANT;
     __JSVAL_VAR(*val) = v = heap_alloc(sizeof(VARIANT));
 
     __JSVAL_TYPE(*val) = JSV_VARIANT;
     __JSVAL_VAR(*val) = v = heap_alloc(sizeof(VARIANT));
-    if(!v)
+    if(!v) {
+        *val = jsval_undefined();
         return E_OUTOFMEMORY;
         return E_OUTOFMEMORY;
+    }
 
     V_VT(v) = VT_EMPTY;
     hres = VariantCopy(v, var);
 
     V_VT(v) = VT_EMPTY;
     hres = VariantCopy(v, var);
-    if(FAILED(hres))
+    if(FAILED(hres)) {
+        *val = jsval_undefined();
         heap_free(v);
         heap_free(v);
+    }
     return hres;
 }
 
     return hres;
 }
 
@@ -382,7 +386,7 @@ HRESULT to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *ret, hint_t hint)
             return S_OK;
         }
 
             return S_OK;
         }
 
-        jsdisp = iface_to_jsdisp((IUnknown*)get_object(val));
+        jsdisp = iface_to_jsdisp(get_object(val));
         if(!jsdisp)
             return disp_propget(ctx, get_object(val), DISPID_VALUE, ret);
 
         if(!jsdisp)
             return disp_propget(ctx, get_object(val), DISPID_VALUE, ret);
 
index 86cbebb..2b21b96 100644 (file)
@@ -255,6 +255,9 @@ static HRESULT ObjectConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags
 
     switch(flags) {
     case DISPATCH_METHOD:
 
     switch(flags) {
     case DISPATCH_METHOD:
+    case DISPATCH_CONSTRUCT: {
+        jsdisp_t *obj;
+
         if(argc) {
             if(!is_undefined(argv[0]) && !is_null(argv[0]) && (!is_object_instance(argv[0]) || get_object(argv[0]))) {
                 IDispatch *disp;
         if(argc) {
             if(!is_undefined(argv[0]) && !is_null(argv[0]) && (!is_object_instance(argv[0]) || get_object(argv[0]))) {
                 IDispatch *disp;
@@ -270,9 +273,6 @@ static HRESULT ObjectConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags
                 return S_OK;
             }
         }
                 return S_OK;
             }
         }
-        /* fall through */
-    case DISPATCH_CONSTRUCT: {
-        jsdisp_t *obj;
 
         hres = create_object(ctx, NULL, &obj);
         if(FAILED(hres))
 
         hres = create_object(ctx, NULL, &obj);
         if(FAILED(hres))
index 2bc8ff6..a797d08 100644 (file)
@@ -296,6 +296,7 @@ typedef struct _function_expression_t {
     source_elements_t *source_elements;
     const WCHAR *src_str;
     DWORD src_len;
     source_elements_t *source_elements;
     const WCHAR *src_str;
     DWORD src_len;
+    unsigned func_id;
 
     struct _function_expression_t *next; /* for compiler */
 } function_expression_t;
 
     struct _function_expression_t *next; /* for compiler */
 } function_expression_t;
index 02527dc..7e414dd 100644 (file)
@@ -628,7 +628,7 @@ static HRESULT String_match(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi
     }
 
     if(is_object_instance(argv[0])) {
     }
 
     if(is_object_instance(argv[0])) {
-        regexp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
+        regexp = iface_to_jsdisp(get_object(argv[0]));
         if(regexp && !is_class(regexp, JSCLASS_REGEXP)) {
             jsdisp_release(regexp);
             regexp = NULL;
         if(regexp && !is_class(regexp, JSCLASS_REGEXP)) {
             jsdisp_release(regexp);
             regexp = NULL;
@@ -791,7 +791,7 @@ static HRESULT String_replace(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un
     }
 
     if(is_object_instance(argv[0])) {
     }
 
     if(is_object_instance(argv[0])) {
-        regexp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
+        regexp = iface_to_jsdisp(get_object(argv[0]));
         if(regexp && !is_class(regexp, JSCLASS_REGEXP)) {
             jsdisp_release(regexp);
             regexp = NULL;
         if(regexp && !is_class(regexp, JSCLASS_REGEXP)) {
             jsdisp_release(regexp);
             regexp = NULL;
@@ -808,7 +808,7 @@ static HRESULT String_replace(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un
 
     if(argc >= 2) {
         if(is_object_instance(argv[1])) {
 
     if(argc >= 2) {
         if(is_object_instance(argv[1])) {
-            rep_func = iface_to_jsdisp((IUnknown*)get_object(argv[1]));
+            rep_func = iface_to_jsdisp(get_object(argv[1]));
             if(rep_func && !is_class(rep_func, JSCLASS_FUNCTION)) {
                 jsdisp_release(rep_func);
                 rep_func = NULL;
             if(rep_func && !is_class(rep_func, JSCLASS_FUNCTION)) {
                 jsdisp_release(rep_func);
                 rep_func = NULL;
@@ -1009,7 +1009,7 @@ static HRESULT String_search(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, uns
     }
 
     if(is_object_instance(argv[0])) {
     }
 
     if(is_object_instance(argv[0])) {
-        regexp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
+        regexp = iface_to_jsdisp(get_object(argv[0]));
         if(regexp && !is_class(regexp, JSCLASS_REGEXP)) {
             jsdisp_release(regexp);
             regexp = NULL;
         if(regexp && !is_class(regexp, JSCLASS_REGEXP)) {
             jsdisp_release(regexp);
             regexp = NULL;
@@ -1153,7 +1153,7 @@ static HRESULT String_split(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi
     }
 
     if(is_object_instance(argv[0])) {
     }
 
     if(is_object_instance(argv[0])) {
-        regexp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
+        regexp = iface_to_jsdisp(get_object(argv[0]));
         if(regexp) {
             if(!is_class(regexp, JSCLASS_REGEXP)) {
                 jsdisp_release(regexp);
         if(regexp) {
             if(!is_class(regexp, JSCLASS_REGEXP)) {
                 jsdisp_release(regexp);
index 8096c8d..c474e10 100644 (file)
@@ -85,7 +85,7 @@ reactos/dll/win32/inseng              # Synced to WineStaging-1.9.11
 reactos/dll/win32/iphlpapi            # Out of sync
 reactos/dll/win32/itircl              # Synced to WineStaging-1.9.11
 reactos/dll/win32/itss                # Synced to WineStaging-1.9.11
 reactos/dll/win32/iphlpapi            # Out of sync
 reactos/dll/win32/itircl              # Synced to WineStaging-1.9.11
 reactos/dll/win32/itss                # Synced to WineStaging-1.9.11
-reactos/dll/win32/jscript             # Synced to WineStaging-1.9.11
+reactos/dll/win32/jscript             # Synced to WineStaging-1.9.16
 reactos/dll/win32/jsproxy             # Synced to WineStaging-1.9.11
 reactos/dll/win32/loadperf            # Synced to WineStaging-1.9.11
 reactos/dll/win32/localspl            # Synced to WineStaging-1.9.11
 reactos/dll/win32/jsproxy             # Synced to WineStaging-1.9.11
 reactos/dll/win32/loadperf            # Synced to WineStaging-1.9.11
 reactos/dll/win32/localspl            # Synced to WineStaging-1.9.11