jscript: Use a jsdisp to hold refs for scopes.

So the garbage collector can traverse it.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
This commit is contained in:
Gabriel Ivăncescu 2022-12-08 17:02:50 +02:00 committed by Alexandre Julliard
parent 07761336d6
commit b0db79d769
2 changed files with 41 additions and 26 deletions

View file

@ -422,15 +422,40 @@ static inline void clear_acc(script_ctx_t *ctx)
ctx->acc = jsval_undefined();
}
static HRESULT scope_push(scope_chain_t *scope, jsdisp_t *jsobj, IDispatch *obj, scope_chain_t **ret)
static void scope_destructor(jsdisp_t *dispex)
{
scope_chain_t *scope = CONTAINING_RECORD(dispex, scope_chain_t, dispex);
if(scope->next)
scope_release(scope->next);
if(scope->obj)
IDispatch_Release(scope->obj);
free(scope);
}
static const builtin_info_t scope_info = {
JSCLASS_NONE,
NULL,
0,
NULL,
scope_destructor,
};
static HRESULT scope_push(script_ctx_t *ctx, scope_chain_t *scope, jsdisp_t *jsobj, IDispatch *obj, scope_chain_t **ret)
{
scope_chain_t *new_scope;
HRESULT hres;
new_scope = malloc(sizeof(scope_chain_t));
new_scope = calloc(1, sizeof(scope_chain_t));
if(!new_scope)
return E_OUTOFMEMORY;
new_scope->ref = 1;
hres = init_dispex(&new_scope->dispex, ctx, &scope_info, NULL);
if(FAILED(hres)) {
free(new_scope);
return hres;
}
if (obj)
IDispatch_AddRef(obj);
@ -453,19 +478,6 @@ static void scope_pop(scope_chain_t **scope)
scope_release(tmp);
}
void scope_release(scope_chain_t *scope)
{
if(--scope->ref)
return;
if(scope->next)
scope_release(scope->next);
if (scope->obj)
IDispatch_Release(scope->obj);
free(scope);
}
static HRESULT disp_get_id(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name, BSTR name_bstr, DWORD flags, DISPID *id)
{
IDispatchEx *dispex;
@ -975,7 +987,7 @@ static HRESULT interp_push_with_scope(script_ctx_t *ctx)
if(FAILED(hres))
return hres;
hres = scope_push(ctx->call_ctx->scope, to_jsdisp(disp), disp, &ctx->call_ctx->scope);
hres = scope_push(ctx, ctx->call_ctx->scope, to_jsdisp(disp), disp, &ctx->call_ctx->scope);
IDispatch_Release(disp);
return hres;
}
@ -989,7 +1001,7 @@ static HRESULT interp_push_block_scope(script_ctx_t *ctx)
TRACE("scope_index %u.\n", scope_index);
hres = scope_push(ctx->call_ctx->scope, NULL, NULL, &frame->scope);
hres = scope_push(ctx, ctx->call_ctx->scope, NULL, NULL, &frame->scope);
if (FAILED(hres) || !scope_index)
return hres;
@ -1004,7 +1016,7 @@ static HRESULT interp_pop_scope(script_ctx_t *ctx)
{
TRACE("\n");
if(ctx->call_ctx->scope->ref > 1) {
if(ctx->call_ctx->scope->dispex.ref > 1) {
HRESULT hres = detach_variable_object(ctx, ctx->call_ctx, FALSE);
if(FAILED(hres))
ERR("Failed to detach variable object: %08lx\n", hres);
@ -1201,7 +1213,7 @@ static HRESULT interp_enter_catch(script_ctx_t *ctx)
hres = jsdisp_propput_name(scope_obj, ident, v);
jsval_release(v);
if(SUCCEEDED(hres))
hres = scope_push(ctx->call_ctx->scope, scope_obj, to_disp(scope_obj), &ctx->call_ctx->scope);
hres = scope_push(ctx, ctx->call_ctx->scope, scope_obj, to_disp(scope_obj), &ctx->call_ctx->scope);
jsdisp_release(scope_obj);
return hres;
}
@ -2919,7 +2931,7 @@ static void pop_call_frame(script_ctx_t *ctx)
assert(frame->scope == frame->base_scope);
/* If current scope will be kept alive, we need to transfer local variables to its variable object. */
if(frame->scope && frame->scope->ref > 1) {
if(frame->scope && frame->scope->dispex.ref > 1) {
HRESULT hres = detach_variable_object(ctx, frame, TRUE);
if(FAILED(hres))
ERR("Failed to detach variable object: %08lx\n", hres);
@ -3191,7 +3203,7 @@ static HRESULT setup_scope(script_ctx_t *ctx, call_frame_t *frame, scope_chain_t
frame->pop_variables = i;
hres = scope_push(scope_chain, variable_object, to_disp(variable_object), &scope);
hres = scope_push(ctx, scope_chain, variable_object, to_disp(variable_object), &scope);
if(FAILED(hres)) {
stack_popn(ctx, ctx->stack_top - orig_stack);
return hres;

View file

@ -222,7 +222,7 @@ static inline bytecode_t *bytecode_addref(bytecode_t *code)
}
typedef struct _scope_chain_t {
LONG ref;
jsdisp_t dispex; /* FIXME: don't wrap it in a jsdisp (it holds ref and traverse for the garbage collector) */
jsdisp_t *jsobj;
IDispatch *obj;
unsigned int scope_index;
@ -230,14 +230,17 @@ typedef struct _scope_chain_t {
struct _scope_chain_t *next;
} scope_chain_t;
void scope_release(scope_chain_t*) DECLSPEC_HIDDEN;
static inline scope_chain_t *scope_addref(scope_chain_t *scope)
{
scope->ref++;
jsdisp_addref(&scope->dispex);
return scope;
}
static inline void scope_release(scope_chain_t *scope)
{
jsdisp_release(&scope->dispex);
}
struct _jsexcept_t {
HRESULT error;