jscript: Use bytecode for calls on identifier and member expressions.

oldstable
Jacek Caban 2011-12-07 11:00:20 +01:00 committed by Alexandre Julliard
parent 18576b36e4
commit 3aa7cee00e
5 changed files with 178 additions and 66 deletions

View File

@ -154,6 +154,24 @@ static HRESULT push_instr_bstr(compiler_ctx_t *ctx, jsop_t op, const WCHAR *arg)
return S_OK;
}
static HRESULT push_instr_bstr_uint(compiler_ctx_t *ctx, jsop_t op, const WCHAR *arg1, unsigned arg2)
{
unsigned instr;
WCHAR *str;
str = compiler_alloc_bstr(ctx, arg1);
if(!str)
return E_OUTOFMEMORY;
instr = push_instr(ctx, op);
if(instr == -1)
return E_OUTOFMEMORY;
instr_ptr(ctx, instr)->arg1.bstr = str;
instr_ptr(ctx, instr)->arg2.uint = arg2;
return S_OK;
}
static HRESULT push_instr_double(compiler_ctx_t *ctx, jsop_t op, double arg)
{
unsigned instr;
@ -222,6 +240,58 @@ static HRESULT compile_member_expression(compiler_ctx_t *ctx, member_expression_
return push_instr_bstr(ctx, OP_member, expr->identifier);
}
static inline BOOL is_memberid_expr(expression_type_t type)
{
return type == EXPR_IDENT || type == EXPR_MEMBER || type == EXPR_ARRAY;
}
static HRESULT compile_memberid_expression(compiler_ctx_t *ctx, expression_t *expr, unsigned flags)
{
HRESULT hres = S_OK;
switch(expr->type) {
case EXPR_IDENT: {
identifier_expression_t *ident_expr = (identifier_expression_t*)expr;
hres = push_instr_bstr_uint(ctx, OP_identid, ident_expr->identifier, flags);
break;
}
case EXPR_ARRAY: {
array_expression_t *array_expr = (array_expression_t*)expr;
hres = compile_expression(ctx, array_expr->member_expr);
if(FAILED(hres))
return hres;
hres = compile_expression(ctx, array_expr->expression);
if(FAILED(hres))
return hres;
hres = push_instr_uint(ctx, OP_memberid, flags);
break;
}
case EXPR_MEMBER: {
member_expression_t *member_expr = (member_expression_t*)expr;
hres = compile_expression(ctx, member_expr->expression);
if(FAILED(hres))
return hres;
/* FIXME: Potential optimization */
hres = push_instr_str(ctx, OP_str, member_expr->identifier);
if(FAILED(hres))
return hres;
hres = push_instr_uint(ctx, OP_memberid, flags);
break;
}
default:
assert(0);
}
return hres;
}
/* ECMA-262 3rd Edition 11.14 */
static HRESULT compile_comma_expression(compiler_ctx_t *ctx, binary_expression_t *expr)
{
@ -325,6 +395,40 @@ static HRESULT compile_interp_fallback(compiler_ctx_t *ctx, expression_t *expr)
return S_OK;
}
static HRESULT compile_call_expression(compiler_ctx_t *ctx, call_expression_t *expr, BOOL *no_ret)
{
unsigned arg_cnt = 0;
argument_t *arg;
unsigned instr;
HRESULT hres;
if(!is_memberid_expr(expr->expression->type)) {
expr->expr.eval = call_expression_eval;
return compile_interp_fallback(ctx, &expr->expr);
}
hres = compile_memberid_expression(ctx, expr->expression, 0);
if(FAILED(hres))
return hres;
for(arg = expr->argument_list; arg; arg = arg->next) {
hres = compile_expression(ctx, arg->expr);
if(FAILED(hres))
return hres;
arg_cnt++;
}
instr = push_instr(ctx, OP_call_member);
if(instr == -1)
return E_OUTOFMEMORY;
instr_ptr(ctx, instr)->arg1.uint = arg_cnt;
instr_ptr(ctx, instr)->arg2.lng = no_ret == NULL;
if(no_ret)
*no_ret = TRUE;
return S_OK;
}
static HRESULT compile_delete_expression(compiler_ctx_t *ctx, unary_expression_t *expr)
{
HRESULT hres;
@ -373,47 +477,7 @@ static HRESULT compile_assign_expression(compiler_ctx_t *ctx, binary_expression_
{
HRESULT hres;
switch(expr->expression1->type) {
case EXPR_IDENT: {
identifier_expression_t *ident_expr = (identifier_expression_t*)expr->expression1;
hres = push_instr_bstr(ctx, OP_identid, ident_expr->identifier);
if(FAILED(hres))
return hres;
break;
}
case EXPR_ARRAY: {
array_expression_t *array_expr = (array_expression_t*)expr->expression1;
hres = compile_expression(ctx, array_expr->member_expr);
if(FAILED(hres))
return hres;
hres = compile_expression(ctx, array_expr->expression);
if(FAILED(hres))
return hres;
if(push_instr(ctx, OP_memberid) == -1)
return E_OUTOFMEMORY;
break;
}
case EXPR_MEMBER: {
member_expression_t *member_expr = (member_expression_t*)expr->expression1;
hres = compile_expression(ctx, member_expr->expression);
if(FAILED(hres))
return hres;
/* FIXME: Potential optimization */
hres = push_instr_str(ctx, OP_str, member_expr->identifier);
if(FAILED(hres))
return hres;
if(push_instr(ctx, OP_memberid) == -1)
return E_OUTOFMEMORY;
break;
}
default:
if(!is_memberid_expr(expr->expression1->type)) {
hres = compile_expression(ctx, expr->expression1);
if(FAILED(hres))
return hres;
@ -428,6 +492,10 @@ static HRESULT compile_assign_expression(compiler_ctx_t *ctx, binary_expression_
return push_instr_uint(ctx, OP_throw, JS_E_ILLEGAL_ASSIGN);
}
hres = compile_memberid_expression(ctx, expr->expression1, fdexNameEnsure);
if(FAILED(hres))
return hres;
if(op != OP_LAST && push_instr(ctx, OP_refval) == -1)
return E_OUTOFMEMORY;
@ -480,7 +548,7 @@ static HRESULT compile_literal(compiler_ctx_t *ctx, literal_t *literal)
}
}
static HRESULT compile_expression(compiler_ctx_t *ctx, expression_t *expr)
static HRESULT compile_expression_noret(compiler_ctx_t *ctx, expression_t *expr, BOOL *no_ret)
{
switch(expr->type) {
case EXPR_ADD:
@ -507,6 +575,8 @@ static HRESULT compile_expression(compiler_ctx_t *ctx, expression_t *expr)
return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_bneg);
case EXPR_BOR:
return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_or);
case EXPR_CALL:
return compile_call_expression(ctx, (call_expression_t*)expr, no_ret);
case EXPR_COMMA:
return compile_comma_expression(ctx, (binary_expression_t*)expr);
case EXPR_COND:
@ -569,6 +639,11 @@ static HRESULT compile_expression(compiler_ctx_t *ctx, expression_t *expr)
return S_OK;
}
static HRESULT compile_expression(compiler_ctx_t *ctx, expression_t *expr)
{
return compile_expression_noret(ctx, expr, NULL);
}
void release_bytecode(bytecode_t *code)
{
unsigned i;
@ -587,8 +662,9 @@ void release_compiler(compiler_ctx_t *ctx)
heap_free(ctx);
}
HRESULT compile_subscript(parser_ctx_t *parser, expression_t *expr, unsigned *ret_off)
HRESULT compile_subscript(parser_ctx_t *parser, expression_t *expr, BOOL do_ret, unsigned *ret_off)
{
BOOL no_ret = FALSE;
HRESULT hres;
if(!parser->code) {
@ -608,7 +684,7 @@ HRESULT compile_subscript(parser_ctx_t *parser, expression_t *expr, unsigned *re
}
*ret_off = parser->compiler->code_off;
hres = compile_expression(parser->compiler, expr);
hres = compile_expression_noret(parser->compiler, expr, do_ret ? NULL : &no_ret);
if(FAILED(hres))
return hres;

View File

@ -182,12 +182,12 @@ static inline IDispatch *stack_pop_objid(exec_ctx_t *ctx, DISPID *id)
return V_DISPATCH(stack_pop(ctx));
}
static inline IDispatch *stack_top_objid(exec_ctx_t *ctx, DISPID *id)
static inline IDispatch *stack_topn_objid(exec_ctx_t *ctx, unsigned n, DISPID *id)
{
assert(V_VT(stack_top(ctx)) == VT_INT && V_VT(stack_topn(ctx, 1)) == VT_DISPATCH);
assert(V_VT(stack_topn(ctx, n)) == VT_INT && V_VT(stack_topn(ctx, n+1)) == VT_DISPATCH);
*id = V_INT(stack_top(ctx));
return V_DISPATCH(stack_topn(ctx, 1));
*id = V_INT(stack_topn(ctx, n));
return V_DISPATCH(stack_topn(ctx, n+1));
}
static void exprval_release(exprval_t *val)
@ -1638,13 +1638,14 @@ static HRESULT interp_member(exec_ctx_t *ctx)
/* ECMA-262 3rd Edition 11.2.1 */
static HRESULT interp_memberid(exec_ctx_t *ctx)
{
const unsigned arg = ctx->parser->code->instrs[ctx->ip].arg1.lng;
VARIANT *objv, *namev;
IDispatch *obj;
BSTR name;
DISPID id;
HRESULT hres;
TRACE("\n");
TRACE("%x\n", arg);
namev = stack_pop(ctx);
objv = stack_pop(ctx);
@ -1660,11 +1661,16 @@ static HRESULT interp_memberid(exec_ctx_t *ctx)
if(FAILED(hres))
return hres;
hres = disp_get_id(ctx->parser->script, obj, name, fdexNameEnsure, &id);
hres = disp_get_id(ctx->parser->script, obj, name, arg, &id);
SysFreeString(name);
if(FAILED(hres)) {
IDispatch_Release(obj);
return hres;
if(hres == DISP_E_UNKNOWNNAME && !(arg & fdexNameEnsure)) {
obj = NULL;
id = JS_E_INVALID_PROPERTY;
}else {
return hres;
}
}
return stack_push_objid(ctx, obj, id);
@ -1680,7 +1686,7 @@ static HRESULT interp_refval(exec_ctx_t *ctx)
TRACE("\n");
disp = stack_top_objid(ctx, &id);
disp = stack_topn_objid(ctx, 0, &id);
if(!disp)
return throw_reference_error(ctx->parser->script, &ctx->ei, JS_E_ILLEGAL_ASSIGN, NULL);
@ -1817,9 +1823,7 @@ HRESULT call_expression_eval(script_ctx_t *ctx, expression_t *_expr, DWORD flags
hres = throw_type_error(ctx, ei, JS_E_INVALID_PROPERTY, NULL);
break;
case EXPRVAL_IDREF:
hres = disp_call(ctx, exprval.u.idref.disp, exprval.u.idref.id,
DISPATCH_METHOD, &dp, flags & EXPR_NOVAL ? NULL : &var, ei, NULL/*FIXME*/);
break;
assert(0);
case EXPRVAL_INVALID:
hres = throw_type_error(ctx, ei, JS_E_OBJECT_EXPECTED, NULL);
break;
@ -1845,6 +1849,33 @@ HRESULT call_expression_eval(script_ctx_t *ctx, expression_t *_expr, DWORD flags
return S_OK;
}
/* ECMA-262 3rd Edition 11.2.3 */
static HRESULT interp_call_member(exec_ctx_t *ctx)
{
const unsigned argn = ctx->parser->code->instrs[ctx->ip].arg1.uint;
const int do_ret = ctx->parser->code->instrs[ctx->ip].arg2.lng;
IDispatch *obj;
DISPPARAMS dp;
VARIANT v;
DISPID id;
HRESULT hres;
TRACE("%d %d\n", argn, do_ret);
obj = stack_topn_objid(ctx, argn, &id);
if(!obj)
return throw_type_error(ctx->parser->script, &ctx->ei, id, NULL);
jsstack_to_dp(ctx, argn, &dp);
hres = disp_call(ctx->parser->script, obj, id, DISPATCH_METHOD, &dp, do_ret ? &v : NULL, &ctx->ei, NULL/*FIXME*/);
if(FAILED(hres))
return hres;
stack_popn(ctx, argn+2);
return do_ret ? stack_push(ctx, &v) : S_OK;
}
/* ECMA-262 3rd Edition 11.1.1 */
static HRESULT interp_this(exec_ctx_t *ctx)
{
@ -1903,19 +1934,20 @@ static HRESULT interp_ident(exec_ctx_t *ctx)
static HRESULT interp_identid(exec_ctx_t *ctx)
{
const BSTR arg = ctx->parser->code->instrs[ctx->ip].arg1.bstr;
const unsigned flags = ctx->parser->code->instrs[ctx->ip].arg2.uint;
exprval_t exprval;
HRESULT hres;
TRACE("%s\n", debugstr_w(arg));
TRACE("%s %x\n", debugstr_w(arg), flags);
hres = identifier_eval(ctx->parser->script, arg, EXPR_NEWREF, &ctx->ei, &exprval);
hres = identifier_eval(ctx->parser->script, arg, (flags&fdexNameEnsure) ? EXPR_NEWREF : 0, &ctx->ei, &exprval);
if(FAILED(hres))
return hres;
if(exprval.type != EXPRVAL_IDREF) {
WARN("invalid ref\n");
exprval_release(&exprval);
return stack_push_objid(ctx, NULL, -1);
return stack_push_objid(ctx, NULL, JS_E_OBJECT_EXPECTED);
}
return stack_push_objid(ctx, exprval.u.idref.disp, exprval.u.idref.id);
@ -3437,10 +3469,13 @@ static HRESULT interp_expression_eval(script_ctx_t *ctx, expression_t *expr, DWO
return hres;
}
assert(exec_ctx->top == prev_top+1);
assert(exec_ctx->top == prev_top+1 || ((flags&EXPR_NOVAL) && exec_ctx->top == prev_top));
ret->type = EXPRVAL_VARIANT;
ret->u.var = *stack_pop(exec_ctx);
if(exec_ctx->top == prev_top)
V_VT(&ret->u.var) = VT_EMPTY;
else
ret->u.var = *stack_pop(exec_ctx);
return S_OK;
}
@ -3450,7 +3485,7 @@ HRESULT compiled_expression_eval(script_ctx_t *ctx, expression_t *expr, DWORD fl
TRACE("\n");
hres = compile_subscript(ctx->exec_ctx->parser, expr, &expr->instr_off);
hres = compile_subscript(ctx->exec_ctx->parser, expr, !(flags & EXPR_NOVAL), &expr->instr_off);
if(FAILED(hres))
return hres;

View File

@ -46,6 +46,7 @@ typedef struct _func_stack {
X(assign, 1, 0,0) \
X(bool, 1, ARG_INT, 0) \
X(bneg, 1, 0,0) \
X(call_member,1, ARG_UINT, ARG_UINT) \
X(delete, 1, 0,0) \
X(div, 1, 0,0) \
X(double, 1, ARG_SBL, 0) \
@ -54,7 +55,7 @@ typedef struct _func_stack {
X(gt, 1, 0,0) \
X(gteq, 1, 0,0) \
X(ident, 1, ARG_BSTR, 0) \
X(identid, 1, ARG_BSTR, 0) \
X(identid, 1, ARG_BSTR, ARG_INT) \
X(in, 1, 0,0) \
X(int, 1, ARG_INT, 0) \
X(jmp, 0, ARG_ADDR, 0) \
@ -63,7 +64,7 @@ typedef struct _func_stack {
X(lt, 1, 0,0) \
X(lteq, 1, 0,0) \
X(member, 1, ARG_BSTR, 0) \
X(memberid, 1, 0,0) \
X(memberid, 1, ARG_UINT, 0) \
X(minus, 1, 0,0) \
X(mod, 1, 0,0) \
X(mul, 1, 0,0) \
@ -580,4 +581,4 @@ HRESULT assign_and_expression_eval(script_ctx_t*,expression_t*,DWORD,jsexcept_t*
HRESULT compiled_expression_eval(script_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*) DECLSPEC_HIDDEN;
HRESULT compile_subscript(parser_ctx_t*,expression_t*,unsigned*) DECLSPEC_HIDDEN;
HRESULT compile_subscript(parser_ctx_t*,expression_t*,BOOL,unsigned*) DECLSPEC_HIDDEN;

View File

@ -1356,7 +1356,7 @@ static const expression_eval_t expression_eval_table[] = {
array_expression_eval,
member_expression_eval,
compiled_expression_eval,
call_expression_eval,
compiled_expression_eval,
compiled_expression_eval,
function_expression_eval,
identifier_expression_eval,

View File

@ -729,7 +729,7 @@ static HRESULT WINAPI Global_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid,
ok(wFlags == INVOKE_FUNC, "wFlags = %x\n", wFlags);
ok(pdp != NULL, "pdp == NULL\n");
todo_wine ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
ok(!pdp->cArgs, "cArgs = %d\n", pdp->cArgs);
ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);