Author: akhaldi Date: Fri Aug 19 09:36:35 2016 New Revision: 72346
URL: http://svn.reactos.org/svn/reactos?rev=72346&view=rev Log: [JSCRIPT] Sync with Wine Staging 1.9.16. CORE-11866
Modified: trunk/reactos/dll/win32/jscript/array.c trunk/reactos/dll/win32/jscript/compile.c trunk/reactos/dll/win32/jscript/dispex.c trunk/reactos/dll/win32/jscript/engine.c trunk/reactos/dll/win32/jscript/engine.h trunk/reactos/dll/win32/jscript/function.c trunk/reactos/dll/win32/jscript/global.c trunk/reactos/dll/win32/jscript/jscript.c trunk/reactos/dll/win32/jscript/jscript.h trunk/reactos/dll/win32/jscript/json.c trunk/reactos/dll/win32/jscript/jsregexp.c trunk/reactos/dll/win32/jscript/jsutils.c trunk/reactos/dll/win32/jscript/object.c trunk/reactos/dll/win32/jscript/parser.h trunk/reactos/dll/win32/jscript/string.c trunk/reactos/media/doc/README.WINE
Modified: trunk/reactos/dll/win32/jscript/array.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/array.c?r... ============================================================================== --- trunk/reactos/dll/win32/jscript/array.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/jscript/array.c [iso-8859-1] Fri Aug 19 09:36:35 2016 @@ -178,7 +178,7 @@ 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); @@ -688,7 +688,7 @@ 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)
Modified: trunk/reactos/dll/win32/jscript/compile.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/compile.c... ============================================================================== --- trunk/reactos/dll/win32/jscript/compile.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/jscript/compile.c [iso-8859-1] Fri Aug 19 09:36:35 2016 @@ -46,11 +46,12 @@ 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; - - variable_declaration_t *var_head; - variable_declaration_t *var_tail;
function_expression_t *func_head; function_expression_t *func_tail; @@ -399,6 +400,40 @@ 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; @@ -407,7 +442,7 @@ 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: { @@ -866,9 +901,7 @@
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) @@ -961,7 +994,7 @@ 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); @@ -1084,25 +1117,22 @@
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) { - ctx->func->var_cnt++; - iter->global_next = iter->next; - if(!iter->next) - ctx->var_tail = iter; - 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 = 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; } @@ -1300,7 +1330,7 @@ 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)) { @@ -1774,6 +1804,393 @@ 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; @@ -1838,35 +2255,20 @@ 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; - unsigned off, i; + unsigned off, i, j; HRESULT hres;
TRACE("\n");
- ctx->var_head = ctx->var_tail = NULL; ctx->func_head = ctx->func_tail = NULL; ctx->from_eval = from_eval; - - off = ctx->code_off; 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) { + parameter_t *param_iter; + if(func_expr->identifier) { func->name = compiler_alloc_bstr(ctx, func_expr->identifier); if(!func->name) @@ -1878,10 +2280,6 @@ 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; @@ -1900,27 +2298,69 @@ } }
+ 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;
- 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; - } - - assert(i == func->var_cnt); + 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(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));
+ 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; + + 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); @@ -2030,6 +2470,7 @@
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;
Modified: trunk/reactos/dll/win32/jscript/dispex.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/dispex.c?... ============================================================================== --- trunk/reactos/dll/win32/jscript/dispex.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/jscript/dispex.c [iso-8859-1] Fri Aug 19 09:36:35 2016 @@ -18,13 +18,6 @@
#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
@@ -491,10 +484,8 @@ 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(); - return hres; - } + if(FAILED(hres)) + return hres;
if(This->builtin_info->on_put) This->builtin_info->on_put(This, prop->name); @@ -558,11 +549,6 @@ }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; @@ -584,6 +570,7 @@ { 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; @@ -1007,7 +994,7 @@ }
if(is_object_instance(val)) - prot = iface_to_jsdisp((IUnknown*)get_object(val)); + prot = iface_to_jsdisp(get_object(val)); jsval_release(val); }
@@ -1018,16 +1005,11 @@ return hres; }
-jsdisp_t *iface_to_jsdisp(IUnknown *iface) -{ - jsdisp_t *ret; - HRESULT hres; - - hres = IUnknown_QueryInterface(iface, &IID_IDispatchJS, (void**)&ret); - if(FAILED(hres)) - return NULL; - - return ret; +jsdisp_t *iface_to_jsdisp(IDispatch *iface) +{ + 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) @@ -1107,7 +1089,7 @@ 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"); @@ -1200,7 +1182,7 @@
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); @@ -1339,7 +1321,7 @@ jsdisp_t *jsdisp; HRESULT hres;
- jsdisp = iface_to_jsdisp((IUnknown*)disp); + jsdisp = iface_to_jsdisp(disp); if(jsdisp) { dispex_prop_t *prop;
@@ -1444,7 +1426,7 @@ 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); @@ -1495,7 +1477,7 @@ jsdisp_t *jsdisp; HRESULT hres;
- jsdisp = iface_to_jsdisp((IUnknown*)disp); + jsdisp = iface_to_jsdisp(disp); if(jsdisp) { dispex_prop_t *prop;
@@ -1531,7 +1513,7 @@ BSTR bstr; HRESULT hres;
- jsdisp = iface_to_jsdisp((IUnknown*)disp); + jsdisp = iface_to_jsdisp(disp); if(jsdisp) { dispex_prop_t *prop; const WCHAR *ptr;
Modified: trunk/reactos/dll/win32/jscript/engine.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/engine.c?... ============================================================================== --- trunk/reactos/dll/win32/jscript/engine.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/jscript/engine.c [iso-8859-1] Fri Aug 19 09:36:35 2016 @@ -39,6 +39,7 @@ enum { EXPRVAL_JSVAL, EXPRVAL_IDREF, + EXPRVAL_STACK_REF, EXPRVAL_INVALID } type; union { @@ -47,6 +48,8 @@ IDispatch *disp; DISPID id; } idref; + unsigned off; + HRESULT hres; } u; } exprval_t;
@@ -85,27 +88,21 @@ 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_ref(script_ctx_t *ctx, unsigned n) +{ + assert(ctx->stack_top > ctx->call_ctx->stack_base+n); + return ctx->stack+ctx->stack_top-1-n; +} + static inline jsval_t stack_topn(script_ctx_t *ctx, unsigned n) { - assert(ctx->stack_top > ctx->call_ctx->stack_base+n); - return ctx->stack[ctx->stack_top-1-n]; + return *stack_top_ref(ctx, n); }
static inline jsval_t *stack_args(script_ctx_t *ctx, unsigned n) @@ -167,32 +164,178 @@ return to_uint32(ctx, stack_pop(ctx), r); }
-static inline IDispatch *stack_pop_objid(script_ctx_t *ctx, DISPID *id) -{ - assert(is_number(stack_top(ctx)) && is_object_instance(stack_topn(ctx, 1))); - - *id = get_number(stack_pop(ctx)); - return get_object(stack_pop(ctx)); -} - -static inline IDispatch *stack_topn_objid(script_ctx_t *ctx, unsigned n, DISPID *id) -{ - assert(is_number(stack_topn(ctx, n)) && is_object_instance(stack_topn(ctx, n+1))); - - *id = get_number(stack_topn(ctx, n)); - return get_object(stack_topn(ctx, n+1)); -} - -static inline jsval_t steal_ret(call_frame_t *frame) -{ - jsval_t r = frame->ret; - frame->ret = jsval_undefined(); - return r; -} - -static inline void clear_ret(call_frame_t *frame) -{ - jsval_release(steal_ret(frame)); +static inline unsigned local_off(call_frame_t *frame, int ref) +{ + return ref < 0 + ? frame->arguments_off - ref-1 + : frame->variables_off + ref; +} + +static inline BSTR local_name(call_frame_t *frame, int ref) +{ + return ref < 0 ? frame->function->params[-ref-1] : frame->function->variables[ref].name; +} + +/* Steals input reference even on failure. */ +static HRESULT stack_push_exprval(script_ctx_t *ctx, exprval_t *val) +{ + 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; + } + + assert(0); + return E_FAIL; +} + +static BOOL stack_topn_exprval(script_ctx_t *ctx, unsigned n, exprval_t *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 BOOL stack_pop_exprval(script_ctx_t *ctx, exprval_t *r) +{ + 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) @@ -205,42 +348,40 @@ if(val->u.idref.disp) IDispatch_Release(val->u.idref.disp); return; + case EXPRVAL_STACK_REF: 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) -{ - 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); - } - - ERR("type %d\n", val->type); - return E_FAIL; -} - -static void exprval_set_idref(exprval_t *val, IDispatch *disp, DISPID id) -{ - val->type = EXPRVAL_IDREF; - val->u.idref.disp = disp; - val->u.idref.id = id; - - if(disp) - IDispatch_AddRef(disp); +static inline void exprval_set_exception(exprval_t *val, HRESULT hres) +{ + val->type = EXPRVAL_INVALID; + val->u.hres = hres; +} + +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 inline jsval_t steal_ret(call_frame_t *frame) +{ + jsval_t r = frame->ret; + frame->ret = jsval_undefined(); + return r; +} + +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) @@ -256,13 +397,8 @@ 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; @@ -303,7 +439,7 @@ 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); @@ -416,6 +552,41 @@ 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; @@ -427,7 +598,7 @@ 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; } } @@ -436,6 +607,16 @@ 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) { @@ -448,12 +629,30 @@
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)) { - exprval_set_idref(ret, scope->obj, id); + exprval_set_disp_ref(ret, scope->obj, id); return S_OK; } } @@ -461,7 +660,7 @@
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; }
@@ -498,7 +697,7 @@ 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; }
@@ -542,28 +741,14 @@ 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); - IDispatch *var_obj, *obj = NULL; + IDispatch *obj = NULL; IDispatchEx *dispex; - DISPID id, var_id; + exprval_t prop_ref; + DISPID id; BSTR name = NULL; HRESULT hres;
@@ -572,9 +757,8 @@ 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; }
@@ -606,7 +790,7 @@ 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; @@ -875,6 +1059,7 @@ const WCHAR *name; jsstr_t *name_str; IDispatch *obj; + exprval_t ref; DISPID id; HRESULT hres;
@@ -896,35 +1081,37 @@
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)) { - 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; } }
- 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) { - IDispatch *disp; + exprval_t ref; jsval_t v; - DISPID id; - HRESULT hres; - - TRACE("\n"); - - disp = stack_topn_objid(ctx, 0, &id); - if(!disp) + HRESULT hres; + + TRACE("\n"); + + if(!stack_topn_exprval(ctx, 0, &ref)) 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;
@@ -981,17 +1168,15 @@ 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);
- 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); - 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); }
@@ -1006,29 +1191,98 @@ return stack_push(ctx, jsval_disp(frame->this_obj)); }
+static HRESULT interp_identifier_ref(script_ctx_t *ctx, BSTR identifier, unsigned flags) +{ + exprval_t exprval; + HRESULT hres; + + hres = identifier_eval(ctx, identifier, &exprval); + if(FAILED(hres)) + return hres; + + 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) + return throw_type_error(ctx, exprval.u.hres, identifier); + + hres = exprval_to_value(ctx, &exprval, &v); + if(FAILED(hres)) + return hres; + + return stack_push(ctx, v); +} + +static HRESULT interp_local_ref(script_ctx_t *ctx) +{ + const int arg = get_op_int(ctx, 0); + const unsigned flags = get_op_uint(ctx, 1); + 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; + + TRACE("%d\n", arg); + + 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)], ©); + if(FAILED(hres)) + return hres; + + return stack_push(ctx, copy); +} + /* ECMA-262 3rd Edition 10.1.4 */ static HRESULT interp_ident(script_ctx_t *ctx) { const BSTR arg = get_op_bstr(ctx, 0); - exprval_t exprval; - jsval_t v; - HRESULT hres;
TRACE("%s\n", debugstr_w(arg));
- hres = identifier_eval(ctx, arg, &exprval); - if(FAILED(hres)) - return hres; - - if(exprval.type == EXPRVAL_INVALID) - return throw_type_error(ctx, JS_E_UNDEFINED_VARIABLE, arg); - - hres = exprval_to_value(ctx, &exprval, &v); - exprval_release(&exprval); - if(FAILED(hres)) - return hres; - - return stack_push(ctx, v); + return identifier_value(ctx, arg); }
/* ECMA-262 3rd Edition 10.1.4 */ @@ -1036,32 +1290,10 @@ { const BSTR arg = get_op_bstr(ctx, 0); const unsigned flags = get_op_uint(ctx, 1); - exprval_t exprval; - HRESULT hres;
TRACE("%s %x\n", debugstr_w(arg), flags);
- hres = identifier_eval(ctx, arg, &exprval); - if(FAILED(hres)) - return hres; - - if(exprval.type == EXPRVAL_INVALID && (flags & fdexNameEnsure)) { - DISPID id; - - hres = jsdisp_get_id(ctx->global, arg, fdexNameEnsure, &id); - if(FAILED(hres)) - return hres; - - exprval_set_idref(&exprval, to_disp(ctx->global), id); - } - - if(exprval.type != EXPRVAL_IDREF) { - WARN("invalid ref\n"); - exprval_release(&exprval); - return stack_push_objid(ctx, NULL, JS_E_OBJECT_EXPECTED); - } - - return stack_push_objid(ctx, exprval.u.idref.disp, exprval.u.idref.id); + return interp_identifier_ref(ctx, arg, flags); }
/* ECMA-262 3rd Edition 7.8.1 */ @@ -1310,7 +1542,7 @@ 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"); @@ -1330,7 +1562,7 @@
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)) @@ -1591,6 +1823,9 @@ 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); @@ -1632,7 +1867,7 @@ 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 { @@ -1661,19 +1896,17 @@ static HRESULT interp_typeofid(script_ctx_t *ctx) { const WCHAR *ret; - IDispatch *obj; + exprval_t ref; jsval_t v; - DISPID id; - HRESULT hres; - - TRACE("\n"); - - obj = stack_pop_objid(ctx, &id); - if(!obj) + HRESULT hres; + + TRACE("\n"); + + if(!stack_pop_exprval(ctx, &ref)) 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);
@@ -1700,14 +1933,10 @@ 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); - exprval_release(&exprval); if(FAILED(hres)) return hres;
@@ -1774,28 +2003,26 @@ 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);
- obj = stack_pop_objid(ctx, &id); - if(!obj) + if(!stack_pop_exprval(ctx, &ref)) 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)) - 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); } - IDispatch_Release(obj); + exprval_release(&ref); if(FAILED(hres)) return hres;
@@ -1806,19 +2033,17 @@ static HRESULT interp_preinc(script_ctx_t *ctx) { const int arg = get_op_int(ctx, 0); - IDispatch *obj; + exprval_t ref; double ret; - DISPID id; 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);
- hres = disp_propget(ctx, obj, id, &v); + hres = exprval_propget(ctx, &ref, &v); if(SUCCEEDED(hres)) { double n;
@@ -1826,10 +2051,10 @@ 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;
@@ -2212,8 +2437,7 @@ /* 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;
@@ -2221,14 +2445,13 @@
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); }
- 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; @@ -2241,18 +2464,16 @@ 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; - DISPID id; 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);
- 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;
@@ -2368,23 +2589,38 @@ #undef X };
-static void release_call_frame(call_frame_t *frame) -{ - 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); - } +static void pop_call_frame(script_ctx_t *ctx) +{ + 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->scope) - scope_release(frame->scope); jsval_release(frame->ret); release_bytecode(frame->bytecode); heap_free(frame); @@ -2406,9 +2642,8 @@
stack_popn(ctx, ctx->stack_top-frame->stack_base);
- ctx->call_ctx = frame->prev_frame; flags = frame->flags; - release_call_frame(frame); + pop_call_frame(ctx); if(!(flags & EXEC_RETURN_TO_INTERP)) return exception_hres; } @@ -2481,14 +2716,13 @@ assert(ctx->stack_top == frame->stack_base); assert(frame->scope == frame->base_scope);
- ctx->call_ctx = frame->prev_frame; 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); } - release_call_frame(frame); + pop_call_frame(ctx); if(!return_to_interp) break; }else { @@ -2512,7 +2746,6 @@ return hres;
hres = exprval_to_value(ctx, &exprval, &v); - exprval_release(&exprval); if(FAILED(hres)) return hres;
@@ -2536,8 +2769,85 @@ 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, - 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; @@ -2546,29 +2856,38 @@ 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;
- 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; }
- for(i=0; i < function->var_cnt; i++) { - if(!(flags & EXEC_GLOBAL) || !lookup_global_members(ctx, function->variables[i], NULL)) { - DISPID id = 0; - - hres = jsdisp_get_id(variable_obj, function->variables[i], fdexNameEnsure, &id); - if(FAILED(hres)) - return hres; + 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 = 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 @@ 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; @@ -2584,18 +2903,34 @@ } }
+ 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->function = function; + frame->ret = jsval_undefined(); + frame->argc = argc; frame->bytecode = bytecode_addref(bytecode); - frame->function = function; + + 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->ip = function->instr_off; frame->stack_base = ctx->stack_top; - frame->ret = jsval_undefined(); - if(scope) - frame->base_scope = frame->scope = scope_addref(scope); - if(this_obj) frame->this_obj = this_obj; else if(ctx->host_global) @@ -2606,8 +2941,6 @@
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);
Modified: trunk/reactos/dll/win32/jscript/engine.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/engine.h?... ============================================================================== --- trunk/reactos/dll/win32/jscript/engine.h [iso-8859-1] (original) +++ trunk/reactos/dll/win32/jscript/engine.h [iso-8859-1] Fri Aug 19 09:36:35 2016 @@ -50,6 +50,8 @@ 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) \ @@ -91,7 +93,6 @@ 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)
@@ -128,8 +129,14 @@ } u; } instr_t;
+typedef struct { + BSTR name; + int ref; +} local_ref_t; + typedef struct _function_code_t { BSTR name; + int local_ref; BSTR event_target; unsigned instr_off;
@@ -140,11 +147,19 @@ 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 locals_cnt; + local_ref_t *locals; } function_code_t; + +local_ref_t *lookup_local(const function_code_t*,const WCHAR*) DECLSPEC_HIDDEN;
typedef struct _bytecode_t { LONG ref; @@ -180,6 +195,7 @@ LONG ref; jsdisp_t *jsobj; IDispatch *obj; + struct _call_frame_t *frame; struct _scope_chain_t *next; } scope_chain_t;
@@ -210,6 +226,12 @@ 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;
@@ -219,8 +241,11 @@ #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*, - 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 setup_arguments_object(script_ctx_t*,call_frame_t*) DECLSPEC_HIDDEN; +void detach_arguments_object(jsdisp_t*) DECLSPEC_HIDDEN;
Modified: trunk/reactos/dll/win32/jscript/function.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/function.... ============================================================================== --- trunk/reactos/dll/win32/jscript/function.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/jscript/function.c [iso-8859-1] Fri Aug 19 09:36:35 2016 @@ -32,7 +32,9 @@ 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) @@ -48,6 +50,11 @@ static inline FunctionInstance *function_this(vdisp_t *jsthis) { 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}; @@ -58,61 +65,80 @@ 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()); +static HRESULT Arguments_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static void Arguments_destructor(jsdisp_t *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); + heap_free(arguments); +} + +static unsigned Arguments_idx_length(jsdisp_t *jsdisp) +{ + ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp; + 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 *r) +{ + ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp; + jsval_t *ref; + + 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 */ + 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; + jsval_t *ref; + HRESULT hres; + + TRACE("%p[%u] = %s\n", arguments, idx, debugstr_jsval(val)); + + if((ref = get_argument_ref(arguments, idx))) { + jsval_t copy; + hres = jsval_copy(val, ©); 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) -{ - FIXME("\n"); - return E_NOTIMPL; -} - -static void Arguments_destructor(jsdisp_t *jsdisp) -{ - ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp; - - 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; - return arguments->function->length; -} - -static HRESULT Arguments_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *res) -{ - ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp; - - TRACE("%p[%u]\n", arguments, idx); + + jsval_release(*ref); + *ref = copy; + return S_OK; + }
/* 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); -} - -static HRESULT Arguments_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val) -{ - ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp; - - TRACE("%p[%u] = %s\n", arguments, idx, debugstr_jsval(val)); - - /* 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 = { @@ -126,11 +152,9 @@ 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; - unsigned i; HRESULT hres;
static const WCHAR caleeW[] = {'c','a','l','l','e','e',0}; @@ -145,60 +169,64 @@ return hres; }
- jsdisp_addref(&calee->dispex); - args->function = calee; - args->var_obj = jsdisp_addref(var_obj); - - /* 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))); - } + args->function = function_from_jsdisp(jsdisp_addref(frame->function_instance)); + args->argc = frame->argc; + args->frame = frame; + + 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; }
- *ret = &args->jsdisp; - return S_OK; -} - -static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, unsigned argc, jsval_t *argv, jsdisp_t **ret) -{ - jsdisp_t *var_disp; - 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; - } - - *ret = var_disp; - return S_OK; + frame->arguments_obj = &args->jsdisp; + return S_OK; +} + +void detach_arguments_object(jsdisp_t *args_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; + + /* 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; + } + } + + 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) { - 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) { @@ -211,38 +239,17 @@ return E_FAIL; }
- hres = create_var_disp(ctx, function, argc, argv, &var_disp); - 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; - } - - 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); + hres = create_dispex(ctx, NULL, NULL, &var_disp); + if(FAILED(hres)) + 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); + jsdisp_release(var_disp); return hres; } @@ -419,7 +426,7 @@
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) { @@ -434,7 +441,7 @@ 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); @@ -451,8 +458,20 @@ } }
- 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); @@ -529,11 +548,17 @@ { 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) { + 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; } @@ -775,7 +800,7 @@ 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;
Modified: trunk/reactos/dll/win32/jscript/global.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/global.c?... ============================================================================== --- trunk/reactos/dll/win32/jscript/global.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/jscript/global.c [iso-8859-1] Fri Aug 19 09:36:35 2016 @@ -179,7 +179,7 @@ jsval_t *r) { call_frame_t *frame; - DWORD exec_flags = 0; + DWORD exec_flags = EXEC_EVAL; bytecode_t *code; const WCHAR *src; HRESULT hres; @@ -219,7 +219,7 @@ 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; }
Modified: trunk/reactos/dll/win32/jscript/jscript.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/jscript.c... ============================================================================== --- trunk/reactos/dll/win32/jscript/jscript.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/jscript/jscript.c [iso-8859-1] Fri Aug 19 09:36:35 2016 @@ -99,7 +99,7 @@ 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; @@ -765,7 +765,7 @@ 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);
Modified: trunk/reactos/dll/win32/jscript/jscript.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/jscript.h... ============================================================================== --- trunk/reactos/dll/win32/jscript/jscript.h [iso-8859-1] (original) +++ trunk/reactos/dll/win32/jscript/jscript.h [iso-8859-1] Fri Aug 19 09:36:35 2016 @@ -142,7 +142,7 @@ JSCLASS_JSON } jsclass_t;
-jsdisp_t *iface_to_jsdisp(IUnknown*) DECLSPEC_HIDDEN; +jsdisp_t *iface_to_jsdisp(IDispatch*) DECLSPEC_HIDDEN;
typedef struct { union { @@ -184,7 +184,7 @@ 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;
Modified: trunk/reactos/dll/win32/jscript/json.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/json.c?re... ============================================================================== --- trunk/reactos/dll/win32/jscript/json.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/jscript/json.c [iso-8859-1] Fri Aug 19 09:36:35 2016 @@ -412,7 +412,7 @@ 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)) { @@ -663,7 +663,7 @@ 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;
@@ -721,7 +721,7 @@ 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;
Modified: trunk/reactos/dll/win32/jscript/jsregexp.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/jsregexp.... ============================================================================== --- trunk/reactos/dll/win32/jscript/jsregexp.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/jscript/jsregexp.c [iso-8859-1] Fri Aug 19 09:36:35 2016 @@ -328,6 +328,7 @@
TRACE("\n");
+ jsval_release(regexp->last_index_val); hres = jsval_copy(value, ®exp->last_index_val); if(FAILED(hres)) return hres; @@ -697,7 +698,7 @@ 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; @@ -948,7 +949,7 @@ 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])) {
Modified: trunk/reactos/dll/win32/jscript/jsutils.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/jsutils.c... ============================================================================== --- trunk/reactos/dll/win32/jscript/jsutils.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/jscript/jsutils.c [iso-8859-1] Fri Aug 19 09:36:35 2016 @@ -138,7 +138,7 @@ 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); } @@ -202,13 +202,17 @@
__JSVAL_TYPE(*val) = JSV_VARIANT; __JSVAL_VAR(*val) = v = heap_alloc(sizeof(VARIANT)); - if(!v) + if(!v) { + *val = jsval_undefined(); return E_OUTOFMEMORY; + }
V_VT(v) = VT_EMPTY; hres = VariantCopy(v, var); - if(FAILED(hres)) + if(FAILED(hres)) { + *val = jsval_undefined(); heap_free(v); + } return hres; }
@@ -382,7 +386,7 @@ 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);
Modified: trunk/reactos/dll/win32/jscript/object.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/object.c?... ============================================================================== --- trunk/reactos/dll/win32/jscript/object.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/jscript/object.c [iso-8859-1] Fri Aug 19 09:36:35 2016 @@ -255,6 +255,9 @@
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; @@ -270,9 +273,6 @@ return S_OK; } } - /* fall through */ - case DISPATCH_CONSTRUCT: { - jsdisp_t *obj;
hres = create_object(ctx, NULL, &obj); if(FAILED(hres))
Modified: trunk/reactos/dll/win32/jscript/parser.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/parser.h?... ============================================================================== --- trunk/reactos/dll/win32/jscript/parser.h [iso-8859-1] (original) +++ trunk/reactos/dll/win32/jscript/parser.h [iso-8859-1] Fri Aug 19 09:36:35 2016 @@ -296,6 +296,7 @@ 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;
Modified: trunk/reactos/dll/win32/jscript/string.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/string.c?... ============================================================================== --- trunk/reactos/dll/win32/jscript/string.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/jscript/string.c [iso-8859-1] Fri Aug 19 09:36:35 2016 @@ -628,7 +628,7 @@ }
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; @@ -791,7 +791,7 @@ }
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; @@ -808,7 +808,7 @@
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; @@ -1009,7 +1009,7 @@ }
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; @@ -1153,7 +1153,7 @@ }
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);
Modified: trunk/reactos/media/doc/README.WINE URL: http://svn.reactos.org/svn/reactos/trunk/reactos/media/doc/README.WINE?rev=7... ============================================================================== --- trunk/reactos/media/doc/README.WINE [iso-8859-1] (original) +++ trunk/reactos/media/doc/README.WINE [iso-8859-1] Fri Aug 19 09:36:35 2016 @@ -85,7 +85,7 @@ 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