jscript: Added bytecode version of switch statement.

oldstable
Jacek Caban 2011-12-27 11:16:40 +01:00 committed by Alexandre Julliard
parent abffe88e19
commit c57dd899a4
4 changed files with 131 additions and 1 deletions

View File

@ -1131,6 +1131,108 @@ static HRESULT compile_with_statement(compiler_ctx_t *ctx, with_statement_t *sta
return S_OK;
}
/* ECMA-262 3rd Edition 12.13 */
static HRESULT compile_switch_statement(compiler_ctx_t *ctx, switch_statement_t *stat)
{
unsigned case_cnt = 0, *case_jmps, i, default_jmp;
BOOL have_default = FALSE;
statement_t *stat_iter;
case_clausule_t *iter;
unsigned off_backup;
BOOL prev_no_fallback;
HRESULT hres;
off_backup = ctx->code_off;
hres = compile_expression(ctx, stat->expr);
if(FAILED(hres))
return hres;
for(iter = stat->case_list; iter; iter = iter->next) {
if(iter->expr)
case_cnt++;
}
case_jmps = heap_alloc(case_cnt * sizeof(*case_jmps));
if(!case_jmps)
return E_OUTOFMEMORY;
i = 0;
for(iter = stat->case_list; iter; iter = iter->next) {
if(!iter->expr) {
have_default = TRUE;
continue;
}
hres = compile_expression(ctx, iter->expr);
if(FAILED(hres))
break;
case_jmps[i] = push_instr(ctx, OP_case);
if(case_jmps[i] == -1) {
hres = E_OUTOFMEMORY;
break;
}
i++;
}
if(SUCCEEDED(hres)) {
if(push_instr(ctx, OP_pop) != -1) {
default_jmp = push_instr(ctx, OP_jmp);
if(default_jmp == -1)
hres = E_OUTOFMEMORY;
}else {
hres = E_OUTOFMEMORY;
}
}
if(FAILED(hres)) {
heap_free(case_jmps);
return hres;
}
i = 0;
for(iter = stat->case_list; iter; iter = iter->next) {
while(iter->next && iter->next->stat == iter->stat) {
instr_ptr(ctx, iter->expr ? case_jmps[i++] : default_jmp)->arg1.uint = ctx->code_off;
iter = iter->next;
}
instr_ptr(ctx, iter->expr ? case_jmps[i++] : default_jmp)->arg1.uint = ctx->code_off;
for(stat_iter = iter->stat; stat_iter && (!iter->next || iter->next->stat != stat_iter); stat_iter = stat_iter->next) {
prev_no_fallback = ctx->no_fallback;
ctx->no_fallback = TRUE;
hres = compile_statement(ctx, stat_iter);
ctx->no_fallback = prev_no_fallback;
if(hres == E_NOTIMPL) {
ctx->code_off = off_backup;
stat->stat.eval = switch_statement_eval;
return compile_interp_fallback(ctx, &stat->stat);
}
if(FAILED(hres))
break;
if(stat_iter->next && push_instr(ctx, OP_pop) == -1) {
hres = E_OUTOFMEMORY;
break;
}
}
if(FAILED(hres))
break;
}
heap_free(case_jmps);
if(FAILED(hres))
return hres;
assert(i == case_cnt);
if(!have_default)
instr_ptr(ctx, default_jmp)->arg1.uint = ctx->code_off;
return S_OK;
}
static HRESULT compile_statement(compiler_ctx_t *ctx, statement_t *stat)
{
switch(stat->type) {
@ -1144,6 +1246,8 @@ static HRESULT compile_statement(compiler_ctx_t *ctx, statement_t *stat)
return compile_for_statement(ctx, (for_statement_t*)stat);
case STAT_IF:
return compile_if_statement(ctx, (if_statement_t*)stat);
case STAT_SWITCH:
return compile_switch_statement(ctx, (switch_statement_t*)stat);
case STAT_VAR:
return compile_var_statement(ctx, (var_statement_t*)stat);
case STAT_WHILE:

View File

@ -1073,6 +1073,31 @@ HRESULT labelled_statement_eval(script_ctx_t *ctx, statement_t *stat, return_typ
return E_NOTIMPL;
}
/* ECMA-262 3rd Edition 12.13 */
static HRESULT interp_case(exec_ctx_t *ctx)
{
const unsigned arg = ctx->parser->code->instrs[ctx->ip].arg1.uint;
VARIANT *v;
BOOL b;
HRESULT hres;
TRACE("\n");
v = stack_pop(ctx);
hres = equal2_values(stack_top(ctx), v, &b);
VariantClear(v);
if(FAILED(hres))
return hres;
if(b) {
stack_popn(ctx, 1);
ctx->ip = arg;
}else {
ctx->ip++;
}
return S_OK;
}
/* ECMA-262 3rd Edition 12.13 */
HRESULT switch_statement_eval(script_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
{

View File

@ -52,6 +52,7 @@ typedef struct _func_stack {
X(call, 1, ARG_UINT, ARG_UINT) \
X(call_member,1, ARG_UINT, ARG_UINT) \
X(carray, 1, ARG_UINT, 0) \
X(case, 0, ARG_ADDR, 0) \
X(cnd_nz, 0, ARG_ADDR, 0) \
X(cnd_z, 0, ARG_ADDR, 0) \
X(delete, 1, 0,0) \

View File

@ -846,7 +846,7 @@ static const statement_eval_t stat_eval_table[] = {
compiled_statement_eval,
labelled_statement_eval,
return_statement_eval,
switch_statement_eval,
compiled_statement_eval,
throw_statement_eval,
try_statement_eval,
compiled_statement_eval,