jscript: Moved eval return value logic to specific statement handlers.
This commit is contained in:
parent
86787db2ca
commit
162f2e6be2
|
@ -1016,21 +1016,12 @@ static HRESULT compile_block_statement(compiler_ctx_t *ctx, statement_t *iter)
|
|||
{
|
||||
HRESULT hres;
|
||||
|
||||
/* FIXME: do it only if needed */
|
||||
if(!iter)
|
||||
return push_instr(ctx, OP_undefined) ? S_OK : E_OUTOFMEMORY;
|
||||
|
||||
while(1) {
|
||||
while(iter) {
|
||||
hres = compile_statement(ctx, NULL, iter);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
iter = iter->next;
|
||||
if(!iter)
|
||||
break;
|
||||
|
||||
if(!push_instr(ctx, OP_pop))
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
|
@ -1073,28 +1064,31 @@ static HRESULT compile_variable_list(compiler_ctx_t *ctx, variable_declaration_t
|
|||
/* ECMA-262 3rd Edition 12.2 */
|
||||
static HRESULT compile_var_statement(compiler_ctx_t *ctx, var_statement_t *stat)
|
||||
{
|
||||
HRESULT hres;
|
||||
|
||||
hres = compile_variable_list(ctx, stat->variable_list);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
return push_instr(ctx, OP_undefined) ? S_OK : E_OUTOFMEMORY;
|
||||
return compile_variable_list(ctx, stat->variable_list);
|
||||
}
|
||||
|
||||
/* ECMA-262 3rd Edition 12.4 */
|
||||
static HRESULT compile_expression_statement(compiler_ctx_t *ctx, expression_statement_t *stat)
|
||||
{
|
||||
BOOL no_ret = FALSE;
|
||||
HRESULT hres;
|
||||
|
||||
hres = compile_expression_noret(ctx, stat->expr, &no_ret);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
if(!ctx->from_eval) {
|
||||
BOOL no_ret = FALSE;
|
||||
|
||||
/* FIXME: that's a big potential optimization */
|
||||
if(no_ret && !push_instr(ctx, OP_undefined))
|
||||
return E_OUTOFMEMORY;
|
||||
hres = compile_expression_noret(ctx, stat->expr, &no_ret);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(!no_ret && !push_instr(ctx, OP_pop))
|
||||
return E_OUTOFMEMORY;
|
||||
}else {
|
||||
hres = compile_expression(ctx, stat->expr);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(!push_instr(ctx, OP_setret))
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -1102,7 +1096,7 @@ static HRESULT compile_expression_statement(compiler_ctx_t *ctx, expression_stat
|
|||
/* ECMA-262 3rd Edition 12.5 */
|
||||
static HRESULT compile_if_statement(compiler_ctx_t *ctx, if_statement_t *stat)
|
||||
{
|
||||
unsigned jmp_else, jmp_end;
|
||||
unsigned jmp_else;
|
||||
HRESULT hres;
|
||||
|
||||
hres = compile_expression(ctx, stat->expr);
|
||||
|
@ -1117,23 +1111,24 @@ static HRESULT compile_if_statement(compiler_ctx_t *ctx, if_statement_t *stat)
|
|||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
jmp_end = push_instr(ctx, OP_jmp);
|
||||
if(!jmp_end)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
set_arg_uint(ctx, jmp_else, ctx->code_off);
|
||||
|
||||
if(stat->else_stat) {
|
||||
unsigned jmp_end;
|
||||
|
||||
jmp_end = push_instr(ctx, OP_jmp);
|
||||
if(!jmp_end)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
set_arg_uint(ctx, jmp_else, ctx->code_off);
|
||||
|
||||
hres = compile_statement(ctx, NULL, stat->else_stat);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
set_arg_uint(ctx, jmp_end, ctx->code_off);
|
||||
}else {
|
||||
/* FIXME: We could sometimes avoid it */
|
||||
if(!push_instr(ctx, OP_undefined))
|
||||
return E_OUTOFMEMORY;
|
||||
set_arg_uint(ctx, jmp_else, ctx->code_off);
|
||||
}
|
||||
|
||||
set_arg_uint(ctx, jmp_end, ctx->code_off);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -1152,12 +1147,9 @@ static HRESULT compile_while_statement(compiler_ctx_t *ctx, while_statement_t *s
|
|||
if(!stat_ctx.continue_label)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
if(!stat->do_while) {
|
||||
/* FIXME: avoid */
|
||||
if(!push_instr(ctx, OP_undefined))
|
||||
return E_OUTOFMEMORY;
|
||||
jmp_off = ctx->code_off;
|
||||
|
||||
jmp_off = ctx->code_off;
|
||||
if(!stat->do_while) {
|
||||
label_set_addr(ctx, stat_ctx.continue_label);
|
||||
hres = compile_expression(ctx, stat->expr);
|
||||
if(FAILED(hres))
|
||||
|
@ -1166,11 +1158,6 @@ static HRESULT compile_while_statement(compiler_ctx_t *ctx, while_statement_t *s
|
|||
hres = push_instr_uint(ctx, OP_jmp_z, stat_ctx.break_label);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(!push_instr(ctx, OP_pop))
|
||||
return E_OUTOFMEMORY;
|
||||
}else {
|
||||
jmp_off = ctx->code_off;
|
||||
}
|
||||
|
||||
hres = compile_statement(ctx, &stat_ctx, stat->statement);
|
||||
|
@ -1186,9 +1173,6 @@ static HRESULT compile_while_statement(compiler_ctx_t *ctx, while_statement_t *s
|
|||
hres = push_instr_uint(ctx, OP_jmp_z, stat_ctx.break_label);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(!push_instr(ctx, OP_pop))
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
hres = push_instr_uint(ctx, OP_jmp, jmp_off);
|
||||
|
@ -1228,10 +1212,6 @@ static HRESULT compile_for_statement(compiler_ctx_t *ctx, for_statement_t *stat)
|
|||
if(!stat_ctx.continue_label)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
/* FIXME: avoid */
|
||||
if(!push_instr(ctx, OP_undefined))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
expr_off = ctx->code_off;
|
||||
|
||||
if(stat->expr) {
|
||||
|
@ -1244,9 +1224,6 @@ static HRESULT compile_for_statement(compiler_ctx_t *ctx, for_statement_t *stat)
|
|||
return hres;
|
||||
}
|
||||
|
||||
if(!push_instr(ctx, OP_pop))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
hres = compile_statement(ctx, &stat_ctx, stat->statement);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
@ -1317,10 +1294,6 @@ static HRESULT compile_forin_statement(compiler_ctx_t *ctx, forin_statement_t *s
|
|||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
/* FIXME: avoid */
|
||||
if(!push_instr(ctx, OP_undefined))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
label_set_addr(ctx, stat_ctx.continue_label);
|
||||
hres = push_instr_uint(ctx, OP_forin, stat_ctx.break_label);
|
||||
if(FAILED(hres))
|
||||
|
@ -1361,7 +1334,6 @@ static HRESULT pop_to_stat(compiler_ctx_t *ctx, BOOL var_stack, BOOL scope_stack
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -1415,9 +1387,6 @@ static HRESULT compile_continue_statement(compiler_ctx_t *ctx, branch_statement_
|
|||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(!push_instr(ctx, OP_undefined))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
return push_instr_uint(ctx, OP_jmp, pop_ctx->continue_label);
|
||||
}
|
||||
|
||||
|
@ -1455,9 +1424,6 @@ static HRESULT compile_break_statement(compiler_ctx_t *ctx, branch_statement_t *
|
|||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(!push_instr(ctx, OP_undefined))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
return push_instr_uint(ctx, OP_jmp, pop_ctx->break_label);
|
||||
}
|
||||
|
||||
|
@ -1475,11 +1441,14 @@ static HRESULT compile_return_statement(compiler_ctx_t *ctx, expression_statemen
|
|||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(stat->expr) {
|
||||
if(stat->expr)
|
||||
hres = compile_expression(ctx, stat->expr);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
else
|
||||
hres = push_instr(ctx, OP_undefined) ? S_OK : E_OUTOFMEMORY;
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
if(!push_instr(ctx, OP_setret))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
hres = pop_to_stat(ctx, FALSE, TRUE, NULL);
|
||||
if(FAILED(hres))
|
||||
|
@ -1607,26 +1576,14 @@ static HRESULT compile_switch_statement(compiler_ctx_t *ctx, switch_statement_t
|
|||
|
||||
set_arg_uint(ctx, iter->expr ? case_jmps[i++] : default_jmp, ctx->code_off);
|
||||
|
||||
if(iter->stat) {
|
||||
for(stat_iter = iter->stat; stat_iter && (!iter->next || iter->next->stat != stat_iter);
|
||||
stat_iter = stat_iter->next) {
|
||||
hres = compile_statement(ctx, &stat_ctx, stat_iter);
|
||||
if(FAILED(hres))
|
||||
break;
|
||||
|
||||
if(stat_iter->next && !push_instr(ctx, OP_pop)) {
|
||||
hres = E_OUTOFMEMORY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(stat_iter = iter->stat; stat_iter && (!iter->next || iter->next->stat != stat_iter);
|
||||
stat_iter = stat_iter->next) {
|
||||
hres = compile_statement(ctx, &stat_ctx, stat_iter);
|
||||
if(FAILED(hres))
|
||||
break;
|
||||
}else {
|
||||
if(!push_instr(ctx, OP_undefined)) {
|
||||
hres = E_OUTOFMEMORY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(FAILED(hres))
|
||||
break;
|
||||
}
|
||||
|
||||
heap_free(case_jmps);
|
||||
|
@ -1639,8 +1596,6 @@ static HRESULT compile_switch_statement(compiler_ctx_t *ctx, switch_statement_t
|
|||
if(FAILED(hres))
|
||||
return hres;
|
||||
set_arg_uint(ctx, default_jmp, ctx->code_off);
|
||||
if(!push_instr(ctx, OP_undefined))
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
label_set_addr(ctx, stat_ctx.break_label);
|
||||
|
@ -1714,10 +1669,6 @@ static HRESULT compile_try_statement(compiler_ctx_t *ctx, try_statement_t *stat)
|
|||
}
|
||||
|
||||
if(stat->finally_statement) {
|
||||
/* FIXME: avoid */
|
||||
if(!push_instr(ctx, OP_pop))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
hres = compile_statement(ctx, stat->catch_block ? NULL : &finally_ctx, stat->finally_statement);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
@ -1749,7 +1700,8 @@ static HRESULT compile_statement(compiler_ctx_t *ctx, statement_ctx_t *stat_ctx,
|
|||
hres = compile_continue_statement(ctx, (branch_statement_t*)stat);
|
||||
break;
|
||||
case STAT_EMPTY:
|
||||
hres = push_instr(ctx, OP_undefined) ? S_OK : E_OUTOFMEMORY; /* FIXME */
|
||||
/* nothing to do */
|
||||
hres = S_OK;
|
||||
break;
|
||||
case STAT_EXPR:
|
||||
hres = compile_expression_statement(ctx, (expression_statement_t*)stat);
|
||||
|
@ -1883,8 +1835,6 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
|
|||
|
||||
resolve_labels(ctx, off);
|
||||
|
||||
if(!from_eval && !push_instr(ctx, OP_pop))
|
||||
return E_OUTOFMEMORY;
|
||||
if(!push_instr(ctx, OP_ret))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
|
|
|
@ -291,6 +291,7 @@ HRESULT create_exec_ctx(script_ctx_t *script_ctx, IDispatch *this_obj, jsdisp_t
|
|||
|
||||
ctx->ref = 1;
|
||||
ctx->is_global = is_global;
|
||||
ctx->ret = jsval_undefined();
|
||||
|
||||
/* ECMA-262 3rd Edition 11.2.3.7 */
|
||||
if(this_obj) {
|
||||
|
@ -340,6 +341,7 @@ void exec_release(exec_ctx_t *ctx)
|
|||
IDispatch_Release(ctx->this_obj);
|
||||
if(ctx->script)
|
||||
script_release(ctx->script);
|
||||
jsval_release(ctx->ret);
|
||||
heap_free(ctx->stack);
|
||||
heap_free(ctx);
|
||||
}
|
||||
|
@ -592,20 +594,16 @@ static HRESULT interp_forin(exec_ctx_t *ctx)
|
|||
IDispatchEx *dispex;
|
||||
DISPID id, var_id;
|
||||
BSTR name = NULL;
|
||||
jsval_t val;
|
||||
HRESULT hres;
|
||||
|
||||
TRACE("\n");
|
||||
|
||||
val = stack_pop(ctx);
|
||||
|
||||
assert(is_number(stack_top(ctx)));
|
||||
id = get_number(stack_top(ctx));
|
||||
|
||||
var_obj = stack_topn_objid(ctx, 1, &var_id);
|
||||
if(!var_obj) {
|
||||
FIXME("invalid ref\n");
|
||||
jsval_release(val);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
|
@ -619,10 +617,8 @@ static HRESULT interp_forin(exec_ctx_t *ctx)
|
|||
if(hres == S_OK)
|
||||
hres = IDispatchEx_GetMemberName(dispex, id, &name);
|
||||
IDispatchEx_Release(dispex);
|
||||
if(FAILED(hres)) {
|
||||
jsval_release(val);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
}else {
|
||||
TRACE("No IDispatchEx\n");
|
||||
}
|
||||
|
@ -636,7 +632,6 @@ static HRESULT interp_forin(exec_ctx_t *ctx)
|
|||
if(!str)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
jsval_release(val);
|
||||
stack_pop(ctx);
|
||||
stack_push(ctx, jsval_number(id)); /* safe, just after pop() */
|
||||
|
||||
|
@ -649,7 +644,6 @@ static HRESULT interp_forin(exec_ctx_t *ctx)
|
|||
}else {
|
||||
stack_popn(ctx, 4);
|
||||
ctx->ip = arg;
|
||||
return stack_push(ctx, val);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -795,8 +789,6 @@ static HRESULT interp_end_finally(exec_ctx_t *ctx)
|
|||
|
||||
TRACE("\n");
|
||||
|
||||
v = stack_pop(ctx);
|
||||
|
||||
assert(is_bool(stack_top(ctx)));
|
||||
if(!get_bool(stack_top(ctx))) {
|
||||
TRACE("passing exception\n");
|
||||
|
@ -809,7 +801,7 @@ static HRESULT interp_end_finally(exec_ctx_t *ctx)
|
|||
}
|
||||
|
||||
stack_popn(ctx, 2);
|
||||
return stack_push(ctx, v);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/* ECMA-262 3rd Edition 13 */
|
||||
|
@ -2361,6 +2353,15 @@ static HRESULT interp_ret(exec_ctx_t *ctx)
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT interp_setret(exec_ctx_t *ctx)
|
||||
{
|
||||
TRACE("\n");
|
||||
|
||||
jsval_release(ctx->ret);
|
||||
ctx->ret = stack_pop(ctx);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
typedef HRESULT (*op_func_t)(exec_ctx_t*);
|
||||
|
||||
static const op_func_t op_funcs[] = {
|
||||
|
@ -2421,10 +2422,6 @@ static HRESULT unwind_exception(exec_ctx_t *ctx)
|
|||
return hres;
|
||||
|
||||
hres = stack_push(ctx, jsval_bool(FALSE));
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
hres = stack_push(ctx, jsval_undefined());
|
||||
}
|
||||
|
||||
return hres;
|
||||
|
@ -2485,11 +2482,10 @@ static HRESULT enter_bytecode(script_ctx_t *ctx, bytecode_t *code, function_code
|
|||
|
||||
assert(exec_ctx->top == prev_top+1 || exec_ctx->top == prev_top);
|
||||
assert(exec_ctx->scope_chain == prev_scope);
|
||||
assert(exec_ctx->top == prev_top);
|
||||
|
||||
if(exec_ctx->top == prev_top)
|
||||
*ret = jsval_undefined();
|
||||
else
|
||||
*ret = stack_pop(exec_ctx);
|
||||
*ret = exec_ctx->ret;
|
||||
exec_ctx->ret = jsval_undefined();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -105,6 +105,7 @@ typedef struct {
|
|||
X(typeofident,1, 0,0) \
|
||||
X(refval, 1, 0,0) \
|
||||
X(ret, 0, 0,0) \
|
||||
X(setret, 1, 0,0) \
|
||||
X(sub, 1, 0,0) \
|
||||
X(undefined, 1, 0,0) \
|
||||
X(var_set, 1, ARG_BSTR, 0) \
|
||||
|
@ -238,6 +239,7 @@ struct _exec_ctx_t {
|
|||
unsigned stack_size;
|
||||
unsigned top;
|
||||
except_frame_t *except_frame;
|
||||
jsval_t ret;
|
||||
|
||||
unsigned ip;
|
||||
};
|
||||
|
|
|
@ -191,6 +191,12 @@ tmp = eval("1,2;");
|
|||
ok(tmp === 2, "tmp = " + tmp);
|
||||
tmp = eval("if(true) {3}");
|
||||
ok(tmp === 3, "tmp = " + tmp);
|
||||
testNoRes();
|
||||
eval("testRes(); testRes()");
|
||||
tmp = eval("3; if(false) {4;} else {};;;")
|
||||
ok(tmp === 3, "tmp = " + tmp);
|
||||
|
||||
tmp = (function(){ return testRes();})();
|
||||
|
||||
var obj1 = new Object();
|
||||
ok(typeof(obj1) === "object", "typeof(obj1) is not object");
|
||||
|
|
|
@ -126,6 +126,8 @@ DEFINE_EXPECT(DeleteMemberByDispID);
|
|||
#define DISPID_GLOBAL_TESTARGTYPES 0x1015
|
||||
#define DISPID_GLOBAL_INTPROP 0x1016
|
||||
#define DISPID_GLOBAL_DISPUNK 0x1017
|
||||
#define DISPID_GLOBAL_TESTRES 0x1018
|
||||
#define DISPID_GLOBAL_TESTNORES 0x1019
|
||||
|
||||
#define DISPID_GLOBAL_TESTPROPDELETE 0x2000
|
||||
|
||||
|
@ -598,6 +600,16 @@ static HRESULT WINAPI Global_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
if(!strcmp_wa(bstrName, "testRes")) {
|
||||
*pid = DISPID_GLOBAL_TESTRES;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if(!strcmp_wa(bstrName, "testNoRes")) {
|
||||
*pid = DISPID_GLOBAL_TESTNORES;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if(strict_dispid_check && strcmp_wa(bstrName, "t"))
|
||||
ok(0, "unexpected call %s\n", wine_dbgstr_w(bstrName));
|
||||
return DISP_E_UNKNOWNNAME;
|
||||
|
@ -735,6 +747,18 @@ static HRESULT WINAPI Global_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid,
|
|||
|
||||
return S_OK;
|
||||
|
||||
case DISPID_GLOBAL_TESTRES:
|
||||
ok(pvarRes != NULL, "pvarRes = NULL\n");
|
||||
if(pvarRes)
|
||||
V_VT(pvarRes) = VT_NULL;
|
||||
return S_OK;
|
||||
|
||||
case DISPID_GLOBAL_TESTNORES:
|
||||
ok(!pvarRes, "pvarRes != NULL\n");
|
||||
if(pvarRes)
|
||||
V_VT(pvarRes) = VT_NULL;
|
||||
return S_OK;
|
||||
|
||||
case DISPID_GLOBAL_TESTOBJ:
|
||||
ok(wFlags == INVOKE_PROPERTYGET, "wFlags = %x\n", wFlags);
|
||||
ok(pdp != NULL, "pdp == NULL\n");
|
||||
|
|
Loading…
Reference in New Issue