jscript: Allow accessing arguments values directly from stack.
Signed-off-by: Jacek Caban <jacek@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
abba963006
commit
da02140b43
|
@ -50,6 +50,7 @@ typedef struct {
|
||||||
enum {
|
enum {
|
||||||
EXPRVAL_JSVAL,
|
EXPRVAL_JSVAL,
|
||||||
EXPRVAL_IDREF,
|
EXPRVAL_IDREF,
|
||||||
|
EXPRVAL_STACK_REF,
|
||||||
EXPRVAL_INVALID
|
EXPRVAL_INVALID
|
||||||
} type;
|
} type;
|
||||||
union {
|
union {
|
||||||
|
@ -58,6 +59,7 @@ typedef struct {
|
||||||
IDispatch *disp;
|
IDispatch *disp;
|
||||||
DISPID id;
|
DISPID id;
|
||||||
} idref;
|
} idref;
|
||||||
|
unsigned off;
|
||||||
HRESULT hres;
|
HRESULT hres;
|
||||||
} u;
|
} u;
|
||||||
} exprval_t;
|
} exprval_t;
|
||||||
|
@ -103,10 +105,15 @@ static inline jsval_t stack_top(script_ctx_t *ctx)
|
||||||
return ctx->stack[ctx->stack_top-1];
|
return ctx->stack[ctx->stack_top-1];
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline jsval_t stack_topn(script_ctx_t *ctx, unsigned n)
|
static inline jsval_t *stack_top_ref(script_ctx_t *ctx, unsigned n)
|
||||||
{
|
{
|
||||||
assert(ctx->stack_top > ctx->call_ctx->stack_base+n);
|
assert(ctx->stack_top > ctx->call_ctx->stack_base+n);
|
||||||
return ctx->stack[ctx->stack_top-1-n];
|
return ctx->stack+ctx->stack_top-1-n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline jsval_t stack_topn(script_ctx_t *ctx, unsigned n)
|
||||||
|
{
|
||||||
|
return *stack_top_ref(ctx, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline jsval_t *stack_args(script_ctx_t *ctx, unsigned n)
|
static inline jsval_t *stack_args(script_ctx_t *ctx, unsigned n)
|
||||||
|
@ -183,6 +190,11 @@ static HRESULT stack_push_exprval(script_ctx_t *ctx, exprval_t *val)
|
||||||
else
|
else
|
||||||
IDispatch_Release(val->u.idref.disp);
|
IDispatch_Release(val->u.idref.disp);
|
||||||
return hres;
|
return hres;
|
||||||
|
case EXPRVAL_STACK_REF:
|
||||||
|
hres = stack_push(ctx, jsval_number(val->u.off));
|
||||||
|
if(SUCCEEDED(hres))
|
||||||
|
hres = stack_push(ctx, jsval_undefined());
|
||||||
|
return hres;
|
||||||
case EXPRVAL_INVALID:
|
case EXPRVAL_INVALID:
|
||||||
hres = stack_push(ctx, jsval_undefined());
|
hres = stack_push(ctx, jsval_undefined());
|
||||||
if(SUCCEEDED(hres))
|
if(SUCCEEDED(hres))
|
||||||
|
@ -194,19 +206,50 @@ static HRESULT stack_push_exprval(script_ctx_t *ctx, exprval_t *val)
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL exprval_from_stack(jsval_t v1, jsval_t v2, exprval_t *r)
|
static BOOL stack_topn_exprval(script_ctx_t *ctx, unsigned n, exprval_t *r)
|
||||||
{
|
{
|
||||||
switch(jsval_type(v1)) {
|
jsval_t v = stack_topn(ctx, n+1);
|
||||||
|
|
||||||
|
switch(jsval_type(v)) {
|
||||||
|
case JSV_NUMBER: {
|
||||||
|
call_frame_t *frame = ctx->call_ctx;
|
||||||
|
unsigned off = get_number(v);
|
||||||
|
|
||||||
|
if(!frame->base_scope->frame && off >= frame->arguments_off) {
|
||||||
|
DISPID id;
|
||||||
|
HRESULT hres;
|
||||||
|
|
||||||
|
/* Got stack reference in deoptimized code. Need to convert it back to variable object reference. */
|
||||||
|
|
||||||
|
hres = jsdisp_get_id(ctx->call_ctx->base_scope->jsobj, frame->function->params[off - frame->arguments_off], 0, &id);
|
||||||
|
if(FAILED(hres)) {
|
||||||
|
r->type = EXPRVAL_INVALID;
|
||||||
|
r->u.hres = hres;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*stack_top_ref(ctx, n+1) = jsval_obj(jsdisp_addref(frame->base_scope->jsobj));
|
||||||
|
*stack_top_ref(ctx, n) = jsval_number(id);
|
||||||
|
r->type = EXPRVAL_IDREF;
|
||||||
|
r->u.idref.disp = frame->base_scope->obj;
|
||||||
|
r->u.idref.id = id;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->type = EXPRVAL_STACK_REF;
|
||||||
|
r->u.off = off;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
case JSV_OBJECT:
|
case JSV_OBJECT:
|
||||||
r->type = EXPRVAL_IDREF;
|
r->type = EXPRVAL_IDREF;
|
||||||
r->u.idref.disp = get_object(v1);
|
r->u.idref.disp = get_object(v);
|
||||||
assert(is_number(v2));
|
assert(is_number(stack_topn(ctx, n)));
|
||||||
r->u.idref.id = get_number(v2);
|
r->u.idref.id = get_number(stack_topn(ctx, n));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
case JSV_UNDEFINED:
|
case JSV_UNDEFINED:
|
||||||
r->type = EXPRVAL_INVALID;
|
r->type = EXPRVAL_INVALID;
|
||||||
assert(is_number(v2));
|
assert(is_number(stack_topn(ctx, n)));
|
||||||
r->u.hres = get_number(v2);
|
r->u.hres = get_number(stack_topn(ctx, n));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
|
@ -216,31 +259,59 @@ static BOOL exprval_from_stack(jsval_t v1, jsval_t v2, exprval_t *r)
|
||||||
|
|
||||||
static inline BOOL stack_pop_exprval(script_ctx_t *ctx, exprval_t *r)
|
static inline BOOL stack_pop_exprval(script_ctx_t *ctx, exprval_t *r)
|
||||||
{
|
{
|
||||||
jsval_t v = stack_pop(ctx);
|
BOOL ret = stack_topn_exprval(ctx, 0, r);
|
||||||
return exprval_from_stack(stack_pop(ctx), v, r);
|
ctx->stack_top -= 2;
|
||||||
}
|
return ret;
|
||||||
|
|
||||||
static inline BOOL stack_topn_exprval(script_ctx_t *ctx, unsigned n, exprval_t *r)
|
|
||||||
{
|
|
||||||
return exprval_from_stack(stack_topn(ctx, n+1), stack_topn(ctx, n), r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT exprval_propput(script_ctx_t *ctx, exprval_t *ref, jsval_t v)
|
static HRESULT exprval_propput(script_ctx_t *ctx, exprval_t *ref, jsval_t v)
|
||||||
{
|
{
|
||||||
assert(ref->type == EXPRVAL_IDREF);
|
switch(ref->type) {
|
||||||
return disp_propput(ctx, ref->u.idref.disp, ref->u.idref.id, v);
|
case EXPRVAL_STACK_REF: {
|
||||||
|
jsval_t *r = ctx->stack + ref->u.off;
|
||||||
|
jsval_release(*r);
|
||||||
|
return jsval_copy(v, r);
|
||||||
|
}
|
||||||
|
case EXPRVAL_IDREF:
|
||||||
|
return disp_propput(ctx, ref->u.idref.disp, ref->u.idref.id, v);
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT exprval_propget(script_ctx_t *ctx, exprval_t *ref, jsval_t *r)
|
static HRESULT exprval_propget(script_ctx_t *ctx, exprval_t *ref, jsval_t *r)
|
||||||
{
|
{
|
||||||
assert(ref->type == EXPRVAL_IDREF);
|
switch(ref->type) {
|
||||||
return disp_propget(ctx, ref->u.idref.disp, ref->u.idref.id, r);
|
case EXPRVAL_STACK_REF:
|
||||||
|
return jsval_copy(ctx->stack[ref->u.off], r);
|
||||||
|
case EXPRVAL_IDREF:
|
||||||
|
return disp_propget(ctx, ref->u.idref.disp, ref->u.idref.id, r);
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT exprval_call(script_ctx_t *ctx, exprval_t *ref, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
|
static HRESULT exprval_call(script_ctx_t *ctx, exprval_t *ref, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
|
||||||
{
|
{
|
||||||
assert(ref->type == EXPRVAL_IDREF);
|
switch(ref->type) {
|
||||||
return disp_call(ctx, ref->u.idref.disp, ref->u.idref.id, flags, argc, argv, r);
|
case EXPRVAL_STACK_REF: {
|
||||||
|
jsval_t v = ctx->stack[ref->u.off];
|
||||||
|
|
||||||
|
if(!is_object_instance(v)) {
|
||||||
|
FIXME("invoke %s\n", debugstr_jsval(v));
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return disp_call_value(ctx, get_object(v), NULL, flags, argc, argv, r);
|
||||||
|
}
|
||||||
|
case EXPRVAL_IDREF:
|
||||||
|
return disp_call(ctx, ref->u.idref.disp, ref->u.idref.id, flags, argc, argv, r);
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ECMA-262 3rd Edition 8.7.1 */
|
/* ECMA-262 3rd Edition 8.7.1 */
|
||||||
|
@ -271,6 +342,7 @@ static void exprval_release(exprval_t *val)
|
||||||
if(val->u.idref.disp)
|
if(val->u.idref.disp)
|
||||||
IDispatch_Release(val->u.idref.disp);
|
IDispatch_Release(val->u.idref.disp);
|
||||||
return;
|
return;
|
||||||
|
case EXPRVAL_STACK_REF:
|
||||||
case EXPRVAL_INVALID:
|
case EXPRVAL_INVALID:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -530,9 +602,16 @@ static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *re
|
||||||
if(ctx->call_ctx) {
|
if(ctx->call_ctx) {
|
||||||
for(scope = ctx->call_ctx->scope; scope; scope = scope->next) {
|
for(scope = ctx->call_ctx->scope; scope; scope = scope->next) {
|
||||||
if(scope->frame) {
|
if(scope->frame) {
|
||||||
hres = detach_variable_object(ctx, scope->frame);
|
function_code_t *func = scope->frame->function;
|
||||||
if(FAILED(hres))
|
int i;
|
||||||
return hres;
|
|
||||||
|
for(i = 0; i < func->param_cnt; i++) {
|
||||||
|
if(!strcmpW(identifier, func->params[i])) {
|
||||||
|
ret->type = EXPRVAL_STACK_REF;
|
||||||
|
ret->u.off = scope->frame->arguments_off+i;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(scope->jsobj)
|
if(scope->jsobj)
|
||||||
hres = jsdisp_get_id(scope->jsobj, identifier, fdexNameImplicit, &id);
|
hres = jsdisp_get_id(scope->jsobj, identifier, fdexNameImplicit, &id);
|
||||||
|
@ -1677,6 +1756,9 @@ static HRESULT interp_delete_ident(script_ctx_t *ctx)
|
||||||
return hres;
|
return hres;
|
||||||
|
|
||||||
switch(exprval.type) {
|
switch(exprval.type) {
|
||||||
|
case EXPRVAL_STACK_REF:
|
||||||
|
ret = FALSE;
|
||||||
|
break;
|
||||||
case EXPRVAL_IDREF:
|
case EXPRVAL_IDREF:
|
||||||
hres = disp_delete(exprval.u.idref.disp, exprval.u.idref.id, &ret);
|
hres = disp_delete(exprval.u.idref.disp, exprval.u.idref.id, &ret);
|
||||||
IDispatch_Release(exprval.u.idref.disp);
|
IDispatch_Release(exprval.u.idref.disp);
|
||||||
|
|
Loading…
Reference in New Issue