jscript: Added bytecode version of for..in statement.

This commit is contained in:
Jacek Caban 2011-12-28 12:05:53 +01:00 committed by Alexandre Julliard
parent 209132724a
commit 661241a392
4 changed files with 137 additions and 1 deletions

View File

@ -1097,6 +1097,72 @@ static HRESULT compile_for_statement(compiler_ctx_t *ctx, for_statement_t *stat)
return S_OK; 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 */ /* ECMA-262 3rd Edition 12.10 */
static HRESULT compile_with_statement(compiler_ctx_t *ctx, with_statement_t *stat) 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); return compile_expression_statement(ctx, (expression_statement_t*)stat);
case STAT_FOR: case STAT_FOR:
return compile_for_statement(ctx, (for_statement_t*)stat); return compile_for_statement(ctx, (for_statement_t*)stat);
case STAT_FORIN:
return compile_forin_statement(ctx, (forin_statement_t*)stat);
case STAT_IF: case STAT_IF:
return compile_if_statement(ctx, (if_statement_t*)stat); return compile_if_statement(ctx, (if_statement_t*)stat);
case STAT_LABEL: case STAT_LABEL:

View File

@ -936,6 +936,73 @@ HRESULT forin_statement_eval(script_ctx_t *ctx, statement_t *_stat, return_type_
return S_OK; 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 */ /* ECMA-262 3rd Edition 12.7 */
HRESULT continue_statement_eval(script_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret) HRESULT continue_statement_eval(script_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
{ {

View File

@ -61,6 +61,7 @@ typedef struct _func_stack {
X(double, 1, ARG_SBL, 0) \ X(double, 1, ARG_SBL, 0) \
X(eq, 1, 0,0) \ X(eq, 1, 0,0) \
X(eq2, 1, 0,0) \ X(eq2, 1, 0,0) \
X(forin, 0, ARG_UINT, 0) \
X(func, 1, ARG_FUNC, 0) \ X(func, 1, ARG_FUNC, 0) \
X(gt, 1, 0,0) \ X(gt, 1, 0,0) \
X(gteq, 1, 0,0) \ X(gteq, 1, 0,0) \

View File

@ -842,7 +842,7 @@ static const statement_eval_t stat_eval_table[] = {
compiled_statement_eval, compiled_statement_eval,
compiled_statement_eval, compiled_statement_eval,
compiled_statement_eval, compiled_statement_eval,
forin_statement_eval, compiled_statement_eval,
compiled_statement_eval, compiled_statement_eval,
compiled_statement_eval, compiled_statement_eval,
return_statement_eval, return_statement_eval,