jscript: Use already running interpreter for execution of member source function.
Signed-off-by: Jacek Caban <jacek@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
5a29cc8787
commit
66632091bf
|
@ -377,6 +377,7 @@ static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t
|
||||||
if(prop->name || This->builtin_info->class != JSCLASS_FUNCTION) {
|
if(prop->name || This->builtin_info->class != JSCLASS_FUNCTION) {
|
||||||
vdisp_t vthis;
|
vdisp_t vthis;
|
||||||
|
|
||||||
|
flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
|
||||||
if(jsthis)
|
if(jsthis)
|
||||||
set_disp(&vthis, jsthis);
|
set_disp(&vthis, jsthis);
|
||||||
else
|
else
|
||||||
|
@ -1060,7 +1061,7 @@ HRESULT jsdisp_call_value(jsdisp_t *jsfunc, IDispatch *jsthis, WORD flags, unsig
|
||||||
{
|
{
|
||||||
HRESULT hres;
|
HRESULT hres;
|
||||||
|
|
||||||
assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT)));
|
assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT|DISPATCH_JSCRIPT_INTERNAL_MASK)));
|
||||||
|
|
||||||
if(is_class(jsfunc, JSCLASS_FUNCTION)) {
|
if(is_class(jsfunc, JSCLASS_FUNCTION)) {
|
||||||
hres = Function_invoke(jsfunc, jsthis, flags, argc, argv, r);
|
hres = Function_invoke(jsfunc, jsthis, flags, argc, argv, r);
|
||||||
|
@ -1073,6 +1074,7 @@ HRESULT jsdisp_call_value(jsdisp_t *jsfunc, IDispatch *jsthis, WORD flags, unsig
|
||||||
}
|
}
|
||||||
|
|
||||||
set_disp(&vdisp, jsthis);
|
set_disp(&vdisp, jsthis);
|
||||||
|
flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
|
||||||
hres = jsfunc->builtin_info->value_prop.invoke(jsfunc->ctx, &vdisp, flags, argc, argv, r);
|
hres = jsfunc->builtin_info->value_prop.invoke(jsfunc->ctx, &vdisp, flags, argc, argv, r);
|
||||||
vdisp_release(&vdisp);
|
vdisp_release(&vdisp);
|
||||||
}
|
}
|
||||||
|
@ -1123,6 +1125,7 @@ HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, uns
|
||||||
return hres;
|
return hres;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
|
||||||
if(ret && argc)
|
if(ret && argc)
|
||||||
flags |= DISPATCH_PROPERTYGET;
|
flags |= DISPATCH_PROPERTYGET;
|
||||||
|
|
||||||
|
@ -1187,6 +1190,7 @@ HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, uns
|
||||||
hres = variant_to_jsval(&retv, ret);
|
hres = variant_to_jsval(&retv, ret);
|
||||||
VariantClear(&retv);
|
VariantClear(&retv);
|
||||||
}
|
}
|
||||||
|
|
||||||
return hres;
|
return hres;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1200,7 +1204,7 @@ HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, IDispatch *jsthis, W
|
||||||
unsigned i;
|
unsigned i;
|
||||||
HRESULT hres;
|
HRESULT hres;
|
||||||
|
|
||||||
assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT)));
|
assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT|DISPATCH_JSCRIPT_INTERNAL_MASK)));
|
||||||
|
|
||||||
jsdisp = iface_to_jsdisp((IUnknown*)disp);
|
jsdisp = iface_to_jsdisp((IUnknown*)disp);
|
||||||
if(jsdisp) {
|
if(jsdisp) {
|
||||||
|
@ -1209,6 +1213,7 @@ HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, IDispatch *jsthis, W
|
||||||
return hres;
|
return hres;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
|
||||||
if(r && argc && flags == DISPATCH_METHOD)
|
if(r && argc && flags == DISPATCH_METHOD)
|
||||||
flags |= DISPATCH_PROPERTYGET;
|
flags |= DISPATCH_PROPERTYGET;
|
||||||
|
|
||||||
|
|
|
@ -1002,7 +1002,7 @@ static HRESULT interp_call_member(script_ctx_t *ctx)
|
||||||
return throw_type_error(ctx, id, NULL);
|
return throw_type_error(ctx, id, NULL);
|
||||||
|
|
||||||
clear_ret(frame);
|
clear_ret(frame);
|
||||||
return disp_call(ctx, obj, id, DISPATCH_METHOD,
|
return disp_call(ctx, obj, id, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
|
||||||
argn, stack_args(ctx, argn), do_ret ? &frame->ret : NULL);
|
argn, stack_args(ctx, argn), do_ret ? &frame->ret : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2403,21 +2403,25 @@ static void release_call_frame(call_frame_t *frame)
|
||||||
|
|
||||||
static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres)
|
static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres)
|
||||||
{
|
{
|
||||||
call_frame_t *frame = ctx->call_ctx;
|
|
||||||
except_frame_t *except_frame;
|
except_frame_t *except_frame;
|
||||||
|
call_frame_t *frame;
|
||||||
jsval_t except_val;
|
jsval_t except_val;
|
||||||
BSTR ident;
|
BSTR ident;
|
||||||
HRESULT hres;
|
HRESULT hres;
|
||||||
|
|
||||||
if(!frame->except_frame) {
|
for(frame = ctx->call_ctx; !frame->except_frame; frame = ctx->call_ctx) {
|
||||||
|
DWORD flags;
|
||||||
|
|
||||||
while(frame->scope != frame->base_scope)
|
while(frame->scope != frame->base_scope)
|
||||||
scope_pop(&frame->scope);
|
scope_pop(&frame->scope);
|
||||||
|
|
||||||
stack_popn(ctx, ctx->stack_top-frame->stack_base);
|
stack_popn(ctx, ctx->stack_top-frame->stack_base);
|
||||||
|
|
||||||
ctx->call_ctx = frame->prev_frame;
|
ctx->call_ctx = frame->prev_frame;
|
||||||
|
flags = frame->flags;
|
||||||
release_call_frame(frame);
|
release_call_frame(frame);
|
||||||
return exception_hres;
|
if(!(flags & EXEC_RETURN_TO_INTERP))
|
||||||
|
return exception_hres;
|
||||||
}
|
}
|
||||||
|
|
||||||
except_frame = frame->except_frame;
|
except_frame = frame->except_frame;
|
||||||
|
@ -2472,9 +2476,8 @@ static HRESULT enter_bytecode(script_ctx_t *ctx, jsval_t *r)
|
||||||
|
|
||||||
TRACE("\n");
|
TRACE("\n");
|
||||||
|
|
||||||
frame = ctx->call_ctx;
|
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
|
frame = ctx->call_ctx;
|
||||||
op = frame->bytecode->instrs[frame->ip].op;
|
op = frame->bytecode->instrs[frame->ip].op;
|
||||||
hres = op_funcs[op](ctx);
|
hres = op_funcs[op](ctx);
|
||||||
if(FAILED(hres)) {
|
if(FAILED(hres)) {
|
||||||
|
@ -2484,14 +2487,21 @@ static HRESULT enter_bytecode(script_ctx_t *ctx, jsval_t *r)
|
||||||
if(FAILED(hres))
|
if(FAILED(hres))
|
||||||
return hres;
|
return hres;
|
||||||
}else if(frame->ip == -1) {
|
}else if(frame->ip == -1) {
|
||||||
|
const DWORD return_to_interp = frame->flags & EXEC_RETURN_TO_INTERP;
|
||||||
|
|
||||||
assert(ctx->stack_top == frame->stack_base);
|
assert(ctx->stack_top == frame->stack_base);
|
||||||
assert(frame->scope == frame->base_scope);
|
assert(frame->scope == frame->base_scope);
|
||||||
|
|
||||||
ctx->call_ctx = frame->prev_frame;
|
ctx->call_ctx = frame->prev_frame;
|
||||||
if(r)
|
if(return_to_interp) {
|
||||||
|
clear_ret(ctx->call_ctx);
|
||||||
|
ctx->call_ctx->ret = steal_ret(frame);
|
||||||
|
}else if(r) {
|
||||||
*r = steal_ret(frame);
|
*r = steal_ret(frame);
|
||||||
|
}
|
||||||
release_call_frame(frame);
|
release_call_frame(frame);
|
||||||
break;
|
if(!return_to_interp)
|
||||||
|
break;
|
||||||
}else {
|
}else {
|
||||||
frame->ip += op_move[op];
|
frame->ip += op_move[op];
|
||||||
}
|
}
|
||||||
|
@ -2617,5 +2627,15 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi
|
||||||
frame->prev_frame = ctx->call_ctx;
|
frame->prev_frame = ctx->call_ctx;
|
||||||
ctx->call_ctx = frame;
|
ctx->call_ctx = frame;
|
||||||
|
|
||||||
|
if(flags & EXEC_RETURN_TO_INTERP) {
|
||||||
|
/*
|
||||||
|
* We're called directly from interpreter, so we may just setup call frame and return.
|
||||||
|
* Already running interpreter will take care of execution.
|
||||||
|
*/
|
||||||
|
if(r)
|
||||||
|
*r = jsval_undefined();
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
return enter_bytecode(ctx, r);
|
return enter_bytecode(ctx, r);
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,6 +216,7 @@ typedef struct _call_frame_t {
|
||||||
|
|
||||||
#define EXEC_GLOBAL 0x0001
|
#define EXEC_GLOBAL 0x0001
|
||||||
#define EXEC_CONSTRUCTOR 0x0002
|
#define EXEC_CONSTRUCTOR 0x0002
|
||||||
|
#define EXEC_RETURN_TO_INTERP 0x0004
|
||||||
|
|
||||||
HRESULT exec_source(script_ctx_t*,DWORD,bytecode_t*,function_code_t*,scope_chain_t*,IDispatch*,
|
HRESULT exec_source(script_ctx_t*,DWORD,bytecode_t*,function_code_t*,scope_chain_t*,IDispatch*,
|
||||||
jsdisp_t*,jsdisp_t*,jsdisp_t*,jsval_t*) DECLSPEC_HIDDEN;
|
jsdisp_t*,jsdisp_t*,jsdisp_t*,jsval_t*) DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -202,7 +202,7 @@ static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, un
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj, unsigned argc, jsval_t *argv,
|
static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj, unsigned argc, jsval_t *argv,
|
||||||
BOOL is_constructor, jsval_t *r)
|
BOOL is_constructor, BOOL caller_execs_source, jsval_t *r)
|
||||||
{
|
{
|
||||||
jsdisp_t *var_disp, *arg_disp;
|
jsdisp_t *var_disp, *arg_disp;
|
||||||
scope_chain_t *scope;
|
scope_chain_t *scope;
|
||||||
|
@ -239,6 +239,8 @@ static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDis
|
||||||
if(SUCCEEDED(hres)) {
|
if(SUCCEEDED(hres)) {
|
||||||
DWORD exec_flags = 0;
|
DWORD exec_flags = 0;
|
||||||
|
|
||||||
|
if(caller_execs_source)
|
||||||
|
exec_flags |= EXEC_RETURN_TO_INTERP;
|
||||||
if(is_constructor)
|
if(is_constructor)
|
||||||
exec_flags |= EXEC_CONSTRUCTOR;
|
exec_flags |= EXEC_CONSTRUCTOR;
|
||||||
hres = exec_source(ctx, exec_flags, function->code, function->func_code, scope, this_obj,
|
hres = exec_source(ctx, exec_flags, function->code, function->func_code, scope, this_obj,
|
||||||
|
@ -277,7 +279,7 @@ static HRESULT call_function(script_ctx_t *ctx, FunctionInstance *function, IDis
|
||||||
if(function->value_proc)
|
if(function->value_proc)
|
||||||
return invoke_value_proc(ctx, function, this_obj, DISPATCH_METHOD, argc, argv, r);
|
return invoke_value_proc(ctx, function, this_obj, DISPATCH_METHOD, argc, argv, r);
|
||||||
|
|
||||||
return invoke_source(ctx, function, this_obj, argc, argv, FALSE, r);
|
return invoke_source(ctx, function, this_obj, argc, argv, FALSE, FALSE, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT function_to_string(FunctionInstance *function, jsstr_t **ret)
|
static HRESULT function_to_string(FunctionInstance *function, jsstr_t **ret)
|
||||||
|
@ -312,6 +314,7 @@ static HRESULT function_to_string(FunctionInstance *function, jsstr_t **ret)
|
||||||
|
|
||||||
HRESULT Function_invoke(jsdisp_t *func_this, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
|
HRESULT Function_invoke(jsdisp_t *func_this, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
|
||||||
{
|
{
|
||||||
|
const BOOL caller_execs_source = (flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE) != 0;
|
||||||
FunctionInstance *function;
|
FunctionInstance *function;
|
||||||
|
|
||||||
TRACE("func %p this %p\n", func_this, jsthis);
|
TRACE("func %p this %p\n", func_this, jsthis);
|
||||||
|
@ -319,6 +322,7 @@ HRESULT Function_invoke(jsdisp_t *func_this, IDispatch *jsthis, WORD flags, unsi
|
||||||
assert(is_class(func_this, JSCLASS_FUNCTION));
|
assert(is_class(func_this, JSCLASS_FUNCTION));
|
||||||
function = (FunctionInstance*)func_this;
|
function = (FunctionInstance*)func_this;
|
||||||
|
|
||||||
|
flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
|
||||||
if(function->value_proc)
|
if(function->value_proc)
|
||||||
return invoke_value_proc(function->dispex.ctx, function, jsthis, flags, argc, argv, r);
|
return invoke_value_proc(function->dispex.ctx, function, jsthis, flags, argc, argv, r);
|
||||||
|
|
||||||
|
@ -330,13 +334,13 @@ HRESULT Function_invoke(jsdisp_t *func_this, IDispatch *jsthis, WORD flags, unsi
|
||||||
if(FAILED(hres))
|
if(FAILED(hres))
|
||||||
return hres;
|
return hres;
|
||||||
|
|
||||||
hres = invoke_source(function->dispex.ctx, function, to_disp(this_obj), argc, argv, TRUE, r);
|
hres = invoke_source(function->dispex.ctx, function, to_disp(this_obj), argc, argv, TRUE, FALSE, r);
|
||||||
jsdisp_release(this_obj);
|
jsdisp_release(this_obj);
|
||||||
return hres;
|
return hres;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(flags == DISPATCH_METHOD);
|
assert(flags == DISPATCH_METHOD);
|
||||||
return invoke_source(function->dispex.ctx, function, jsthis, argc, argv, FALSE, r);
|
return invoke_source(function->dispex.ctx, function, jsthis, argc, argv, FALSE, caller_execs_source, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT Function_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
|
static HRESULT Function_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
|
||||||
|
|
|
@ -101,6 +101,14 @@ extern HINSTANCE jscript_hinstance DECLSPEC_HIDDEN;
|
||||||
#define PROPF_CONST 0x0800
|
#define PROPF_CONST 0x0800
|
||||||
#define PROPF_DONTDELETE 0x1000
|
#define PROPF_DONTDELETE 0x1000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is our internal dispatch flag informing calee that it's called directly from interpreter.
|
||||||
|
* If calee is executed as interpreted function, we may let already running interpreter to take
|
||||||
|
* of execution.
|
||||||
|
*/
|
||||||
|
#define DISPATCH_JSCRIPT_CALLEREXECSSOURCE 0x8000
|
||||||
|
#define DISPATCH_JSCRIPT_INTERNAL_MASK DISPATCH_JSCRIPT_CALLEREXECSSOURCE
|
||||||
|
|
||||||
/* NOTE: Keep in sync with names in Object.toString implementation */
|
/* NOTE: Keep in sync with names in Object.toString implementation */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
JSCLASS_NONE,
|
JSCLASS_NONE,
|
||||||
|
|
Loading…
Reference in New Issue