From 661241a392bb90b931e8637f4f3e28f1369bc3a1 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Wed, 28 Dec 2011 12:05:53 +0100 Subject: [PATCH] jscript: Added bytecode version of for..in statement. --- dlls/jscript/compile.c | 68 ++++++++++++++++++++++++++++++++++++++++++ dlls/jscript/engine.c | 67 +++++++++++++++++++++++++++++++++++++++++ dlls/jscript/engine.h | 1 + dlls/jscript/parser.y | 2 +- 4 files changed, 137 insertions(+), 1 deletion(-) diff --git a/dlls/jscript/compile.c b/dlls/jscript/compile.c index 5f255983367..585520d6268 100644 --- a/dlls/jscript/compile.c +++ b/dlls/jscript/compile.c @@ -1097,6 +1097,72 @@ static HRESULT compile_for_statement(compiler_ctx_t *ctx, for_statement_t *stat) return S_OK; } +/* ECMA-262 3rd Edition 12.6.4 */ +static HRESULT compile_forin_statement(compiler_ctx_t *ctx, forin_statement_t *stat) +{ + unsigned loop_addr, off_backup = ctx->code_off; + BOOL prev_no_fallback; + HRESULT hres; + + if(stat->variable) { + hres = compile_variable_list(ctx, stat->variable); + if(FAILED(hres)) + return hres; + } + + hres = compile_expression(ctx, stat->in_expr); + if(FAILED(hres)) + return hres; + + if(stat->variable) { + hres = push_instr_bstr_uint(ctx, OP_identid, stat->variable->identifier, fdexNameEnsure); + if(FAILED(hres)) + return hres; + }else if(is_memberid_expr(stat->expr->type)) { + hres = compile_memberid_expression(ctx, stat->expr, fdexNameEnsure); + if(FAILED(hres)) + return hres; + }else { + hres = push_instr_uint(ctx, OP_throw, JS_E_ILLEGAL_ASSIGN); + if(FAILED(hres)) + return hres; + + /* FIXME: compile statement anyways when we depend on compiler to check errors */ + return S_OK; + } + + hres = push_instr_int(ctx, OP_int, DISPID_STARTENUM); + if(FAILED(hres)) + return hres; + + /* FIXME: avoid */ + if(push_instr(ctx, OP_undefined) == -1) + return E_OUTOFMEMORY; + + loop_addr = ctx->code_off; + if(push_instr(ctx, OP_forin) == -1) + return E_OUTOFMEMORY; + + prev_no_fallback = ctx->no_fallback; + ctx->no_fallback = TRUE; + hres = compile_statement(ctx, stat->statement); + ctx->no_fallback = prev_no_fallback; + if(hres == E_NOTIMPL) { + ctx->code_off = off_backup; + stat->stat.eval = forin_statement_eval; + return compile_interp_fallback(ctx, &stat->stat); + } + if(FAILED(hres)) + return hres; + + hres = push_instr_uint(ctx, OP_jmp, loop_addr); + if(FAILED(hres)) + return hres; + + instr_ptr(ctx, loop_addr)->arg1.uint = ctx->code_off; + return S_OK; +} + /* ECMA-262 3rd Edition 12.10 */ static HRESULT compile_with_statement(compiler_ctx_t *ctx, with_statement_t *stat) { @@ -1244,6 +1310,8 @@ static HRESULT compile_statement(compiler_ctx_t *ctx, statement_t *stat) return compile_expression_statement(ctx, (expression_statement_t*)stat); case STAT_FOR: return compile_for_statement(ctx, (for_statement_t*)stat); + case STAT_FORIN: + return compile_forin_statement(ctx, (forin_statement_t*)stat); case STAT_IF: return compile_if_statement(ctx, (if_statement_t*)stat); case STAT_LABEL: diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index fbeee6ffc4e..f3268ba51d0 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -936,6 +936,73 @@ HRESULT forin_statement_eval(script_ctx_t *ctx, statement_t *_stat, return_type_ return S_OK; } +/* ECMA-262 3rd Edition 12.6.4 */ +static HRESULT interp_forin(exec_ctx_t *ctx) +{ + const HRESULT arg = ctx->parser->code->instrs[ctx->ip].arg1.uint; + IDispatch *var_obj, *obj = NULL; + IDispatchEx *dispex; + DISPID id, var_id; + BSTR name = NULL; + VARIANT *val; + HRESULT hres; + + TRACE("\n"); + + val = stack_pop(ctx); + + assert(V_VT(stack_top(ctx)) == VT_I4); + id = V_I4(stack_top(ctx)); + + var_obj = stack_topn_objid(ctx, 1, &var_id); + if(!var_obj) { + FIXME("invalid ref\n"); + VariantClear(val); + return E_FAIL; + } + + if(V_VT(stack_topn(ctx, 3)) == VT_DISPATCH) + obj = V_DISPATCH(stack_topn(ctx, 3)); + + if(obj) { + hres = IDispatch_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex); + if(SUCCEEDED(hres)) { + hres = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, id, &id); + if(hres == S_OK) + hres = IDispatchEx_GetMemberName(dispex, id, &name); + IDispatchEx_Release(dispex); + if(FAILED(hres)) { + VariantClear(val); + return hres; + } + }else { + TRACE("No IDispatchEx\n"); + } + } + + if(name) { + VARIANT v; + + VariantClear(val); + + V_I4(stack_top(ctx)) = id; + + V_VT(&v) = VT_BSTR; + V_BSTR(&v) = name; + hres = disp_propput(ctx->parser->script, var_obj, var_id, &v, ctx->ei, NULL/*FIXME*/); + SysFreeString(name); + if(FAILED(hres)) + return hres; + + ctx->ip++; + }else { + stack_popn(ctx, 4); + ctx->ip = arg; + return stack_push(ctx, val); + } + return S_OK; +} + /* ECMA-262 3rd Edition 12.7 */ HRESULT continue_statement_eval(script_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret) { diff --git a/dlls/jscript/engine.h b/dlls/jscript/engine.h index 7dbaeb27aeb..b2f2f82c74c 100644 --- a/dlls/jscript/engine.h +++ b/dlls/jscript/engine.h @@ -61,6 +61,7 @@ typedef struct _func_stack { X(double, 1, ARG_SBL, 0) \ X(eq, 1, 0,0) \ X(eq2, 1, 0,0) \ + X(forin, 0, ARG_UINT, 0) \ X(func, 1, ARG_FUNC, 0) \ X(gt, 1, 0,0) \ X(gteq, 1, 0,0) \ diff --git a/dlls/jscript/parser.y b/dlls/jscript/parser.y index 02d35bd3061..a1842028053 100644 --- a/dlls/jscript/parser.y +++ b/dlls/jscript/parser.y @@ -842,7 +842,7 @@ static const statement_eval_t stat_eval_table[] = { compiled_statement_eval, compiled_statement_eval, compiled_statement_eval, - forin_statement_eval, + compiled_statement_eval, compiled_statement_eval, compiled_statement_eval, return_statement_eval,