jscript: Allow garbage collection between different jscript contexts.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
This commit is contained in:
Gabriel Ivăncescu 2023-12-12 19:57:37 +02:00 committed by Alexandre Julliard
parent bc45b43a49
commit 64009b9c9f
3 changed files with 82 additions and 16 deletions

View file

@ -820,13 +820,13 @@ HRESULT gc_run(script_ctx_t *ctx)
for(prop = obj->props, props_end = prop + obj->prop_cnt; prop < props_end; prop++) { for(prop = obj->props, props_end = prop + obj->prop_cnt; prop < props_end; prop++) {
switch(prop->type) { switch(prop->type) {
case PROP_JSVAL: case PROP_JSVAL:
if(is_object_instance(prop->u.val) && (link = to_jsdisp(get_object(prop->u.val))) && link->ctx == ctx) if(is_object_instance(prop->u.val) && (link = to_jsdisp(get_object(prop->u.val))))
link->ref--; link->ref--;
break; break;
case PROP_ACCESSOR: case PROP_ACCESSOR:
if(prop->u.accessor.getter && prop->u.accessor.getter->ctx == ctx) if(prop->u.accessor.getter)
prop->u.accessor.getter->ref--; prop->u.accessor.getter->ref--;
if(prop->u.accessor.setter && prop->u.accessor.setter->ctx == ctx) if(prop->u.accessor.setter)
prop->u.accessor.setter->ref--; prop->u.accessor.setter->ref--;
break; break;
default: default:
@ -834,7 +834,7 @@ HRESULT gc_run(script_ctx_t *ctx)
} }
} }
if(obj->prototype && obj->prototype->ctx == ctx) if(obj->prototype)
obj->prototype->ref--; obj->prototype->ref--;
if(obj->builtin_info->gc_traverse) if(obj->builtin_info->gc_traverse)
obj->builtin_info->gc_traverse(&gc_ctx, GC_TRAVERSE_SPECULATIVELY, obj); obj->builtin_info->gc_traverse(&gc_ctx, GC_TRAVERSE_SPECULATIVELY, obj);
@ -870,12 +870,12 @@ HRESULT gc_run(script_ctx_t *ctx)
default: default:
continue; continue;
} }
if(link && link->gc_marked && link->ctx == ctx) { if(link && link->gc_marked) {
hres = gc_stack_push(&gc_ctx, link); hres = gc_stack_push(&gc_ctx, link);
if(FAILED(hres)) if(FAILED(hres))
break; break;
} }
if(link2 && link2->gc_marked && link2->ctx == ctx) { if(link2 && link2->gc_marked) {
hres = gc_stack_push(&gc_ctx, link2); hres = gc_stack_push(&gc_ctx, link2);
if(FAILED(hres)) if(FAILED(hres))
break; break;
@ -885,7 +885,7 @@ HRESULT gc_run(script_ctx_t *ctx)
if(FAILED(hres)) if(FAILED(hres))
break; break;
if(obj2->prototype && obj2->prototype->gc_marked && obj2->prototype->ctx == ctx) { if(obj2->prototype && obj2->prototype->gc_marked) {
hres = gc_stack_push(&gc_ctx, obj2->prototype); hres = gc_stack_push(&gc_ctx, obj2->prototype);
if(FAILED(hres)) if(FAILED(hres))
break; break;
@ -974,8 +974,6 @@ HRESULT gc_process_linked_obj(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsd
return S_OK; return S_OK;
} }
if(link->ctx != obj->ctx)
return S_OK;
if(op == GC_TRAVERSE_SPECULATIVELY) if(op == GC_TRAVERSE_SPECULATIVELY)
link->ref--; link->ref--;
else if(link->gc_marked) else if(link->gc_marked)
@ -994,7 +992,7 @@ HRESULT gc_process_linked_val(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsd
return S_OK; return S_OK;
} }
if(!is_object_instance(*link) || !(jsdisp = to_jsdisp(get_object(*link))) || jsdisp->ctx != obj->ctx) if(!is_object_instance(*link) || !(jsdisp = to_jsdisp(get_object(*link))))
return S_OK; return S_OK;
if(op == GC_TRAVERSE_SPECULATIVELY) if(op == GC_TRAVERSE_SPECULATIVELY)
jsdisp->ref--; jsdisp->ref--;

View file

@ -745,11 +745,6 @@ static HRESULT WeakMap_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigne
if(!key) if(!key)
return JS_E_KEY_NOT_OBJECT; return JS_E_KEY_NOT_OBJECT;
if(key->ctx != ctx) {
FIXME("different ctx not supported\n");
return JS_E_KEY_NOT_OBJECT;
}
if((entry = get_weakmap_entry(weakmap, key))) { if((entry = get_weakmap_entry(weakmap, key))) {
jsval_t val; jsval_t val;
hres = jsval_copy(value, &val); hres = jsval_copy(value, &val);

View file

@ -3596,9 +3596,14 @@ static void test_destructors(void)
"a.ref = { 'ref': Math, 'a': a }; b.ref = Math.ref;\n" "a.ref = { 'ref': Math, 'a': a }; b.ref = Math.ref;\n"
"a.self = a; b.self = b; c.self = c;\n" "a.self = a; b.self = b; c.self = c;\n"
"})(), true"; "})(), true";
static DISPID propput_dispid = DISPID_PROPERTYPUT;
IActiveScript *script, *script2;
IDispatchEx *dispex, *dispex2;
IActiveScriptParse *parser; IActiveScriptParse *parser;
IActiveScript *script; DISPPARAMS dp = { 0 };
VARIANT v; VARIANT v;
DISPID id;
BSTR str;
HRESULT hres; HRESULT hres;
V_VT(&v) = VT_EMPTY; V_VT(&v) = VT_EMPTY;
@ -3643,6 +3648,74 @@ static void test_destructors(void)
CHECK_CALLED(testdestrobj); CHECK_CALLED(testdestrobj);
IActiveScript_Release(script); IActiveScript_Release(script);
/* Create a cyclic ref across two jscript engines */
V_VT(&v) = VT_EMPTY;
hres = parse_script_expr(cyclic_refs, &v, &script);
ok(hres == S_OK, "parse_script_expr failed: %08lx\n", hres);
ok(V_VT(&v) == VT_BOOL, "V_VT(v) = %d\n", V_VT(&v));
hres = IActiveScript_QueryInterface(script, &IID_IActiveScriptParse, (void**)&parser);
ok(hres == S_OK, "Could not get IActiveScriptParse: %08lx\n", hres);
V_VT(&v) = VT_EMPTY;
hres = IActiveScriptParse_ParseScriptText(parser, L"Math.ref", NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &v, NULL);
ok(hres == S_OK, "ParseScriptText failed: %08lx\n", hres);
ok(V_VT(&v) == VT_DISPATCH, "V_VT(v) = %d\n", V_VT(&v));
ok(V_DISPATCH(&v) != NULL, "V_DISPATCH(v) = NULL\n");
hres = IDispatch_QueryInterface(V_DISPATCH(&v), &IID_IDispatchEx, (void**)&dispex);
ok(hres == S_OK, "Could not get IDispatchEx iface: %08lx\n", hres);
VariantClear(&v);
V_VT(&v) = VT_EMPTY;
hres = parse_script_expr(L"new Object()", &v, &script2);
ok(hres == S_OK, "parse_script_expr failed: %08lx\n", hres);
ok(V_VT(&v) == VT_DISPATCH, "V_VT(v) = %d\n", V_VT(&v));
ok(V_DISPATCH(&v) != NULL, "V_DISPATCH(v) = NULL\n");
hres = IDispatch_QueryInterface(V_DISPATCH(&v), &IID_IDispatchEx, (void**)&dispex2);
ok(hres == S_OK, "Could not get IDispatchEx iface: %08lx\n", hres);
VariantClear(&v);
dp.cArgs = dp.cNamedArgs = 1;
dp.rgdispidNamedArgs = &propput_dispid;
dp.rgvarg = &v;
str = SysAllocString(L"diff_ctx");
hres = IDispatchEx_GetDispID(dispex, str, fdexNameEnsure, &id);
ok(hres == S_OK, "GetDispID failed: %08lx\n", hres);
SysFreeString(str);
V_VT(&v) = VT_DISPATCH;
V_DISPATCH(&v) = (IDispatch*)dispex2;
hres = IDispatchEx_Invoke(dispex, id, &IID_NULL, 0, DISPATCH_PROPERTYPUT, &dp, NULL, NULL, NULL);
ok(hres == S_OK, "Invoke failed: %08lx\n", hres);
str = SysAllocString(L"ref");
hres = IDispatchEx_GetDispID(dispex2, str, fdexNameEnsure, &id);
ok(hres == S_OK, "GetDispID failed: %08lx\n", hres);
SysFreeString(str);
V_VT(&v) = VT_DISPATCH;
V_DISPATCH(&v) = (IDispatch*)dispex;
hres = IDispatchEx_Invoke(dispex2, id, &IID_NULL, 0, DISPATCH_PROPERTYPUT, &dp, NULL, NULL, NULL);
ok(hres == S_OK, "Invoke failed: %08lx\n", hres);
IDispatchEx_Release(dispex2);
IDispatchEx_Release(dispex);
SET_EXPECT(testdestrobj);
V_VT(&v) = VT_EMPTY;
hres = IActiveScriptParse_ParseScriptText(parser, L"Math.ref = undefined, CollectGarbage(), true",
NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &v, NULL);
ok(hres == S_OK, "ParseScriptText failed: %08lx\n", hres);
ok(V_VT(&v) == VT_BOOL, "V_VT(v) = %d\n", V_VT(&v));
IActiveScriptParse_Release(parser);
CHECK_CALLED(testdestrobj);
IActiveScript_Release(script2);
IActiveScript_Release(script);
} }
static void test_eval(void) static void test_eval(void)