-- v3: jscript: Allow garbage collection between different jscript contexts. jscript: Make the garbage collector thread-wide rather than per-ctx. jscript: Don't use atomic compare exchange when setting the script ctx. jscript: Move thread_id from JScript struct to TLS data.
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/jscript.c | 32 +++++++++++++++++++++----------- dlls/jscript/jscript.h | 8 ++++++++ dlls/jscript/jscript_main.c | 31 ++++++++++++++++++++++++++++++- 3 files changed, 59 insertions(+), 12 deletions(-)
diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index b1940b770d3..191747c7173 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -51,8 +51,8 @@ typedef struct { LONG ref;
DWORD safeopt; + struct thread_data *thread_data; script_ctx_t *ctx; - LONG thread_id; LCID lcid; DWORD version; BOOL html_mode; @@ -524,8 +524,10 @@ static void decrease_state(JScript *This, SCRIPTSTATE state) FIXME("NULL ctx\n"); }
- if(state == SCRIPTSTATE_UNINITIALIZED || state == SCRIPTSTATE_CLOSED) - This->thread_id = 0; + if((state == SCRIPTSTATE_UNINITIALIZED || state == SCRIPTSTATE_CLOSED) && This->thread_data) { + release_thread_data(This->thread_data); + This->thread_data = NULL; + }
if(This->site) { IActiveScriptSite_Release(This->site); @@ -708,6 +710,8 @@ static ULONG WINAPI JScript_Release(IActiveScript *iface) This->ctx->active_script = NULL; script_release(This->ctx); } + if(This->thread_data) + release_thread_data(This->thread_data); free(This); unlock_module(); } @@ -726,6 +730,7 @@ static HRESULT WINAPI JScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass) { JScript *This = impl_from_IActiveScript(iface); + struct thread_data *thread_data; named_item_t *item; LCID lcid; HRESULT hres; @@ -738,8 +743,13 @@ static HRESULT WINAPI JScript_SetScriptSite(IActiveScript *iface, if(This->site) return E_UNEXPECTED;
- if(InterlockedCompareExchange(&This->thread_id, GetCurrentThreadId(), 0)) + if(!(thread_data = get_thread_data())) + return E_OUTOFMEMORY; + + if(InterlockedCompareExchangePointer((void**)&This->thread_data, thread_data, NULL)) { + release_thread_data(thread_data); return E_UNEXPECTED; + }
if(!This->ctx) { script_ctx_t *ctx = calloc(1, sizeof(script_ctx_t)); @@ -821,7 +831,7 @@ static HRESULT WINAPI JScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE s
TRACE("(%p)->(%d)\n", This, ss);
- if(This->thread_id && GetCurrentThreadId() != This->thread_id) + if(This->thread_data && This->thread_data->thread_id != GetCurrentThreadId()) return E_UNEXPECTED;
if(ss == SCRIPTSTATE_UNINITIALIZED) { @@ -865,7 +875,7 @@ static HRESULT WINAPI JScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE * if(!pssState) return E_POINTER;
- if(This->thread_id && This->thread_id != GetCurrentThreadId()) + if(This->thread_data && This->thread_data->thread_id != GetCurrentThreadId()) return E_UNEXPECTED;
*pssState = This->ctx ? This->ctx->state : SCRIPTSTATE_UNINITIALIZED; @@ -878,7 +888,7 @@ static HRESULT WINAPI JScript_Close(IActiveScript *iface)
TRACE("(%p)->()\n", This);
- if(This->thread_id && This->thread_id != GetCurrentThreadId()) + if(This->thread_data && This->thread_data->thread_id != GetCurrentThreadId()) return E_UNEXPECTED;
decrease_state(This, SCRIPTSTATE_CLOSED); @@ -897,7 +907,7 @@ static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface,
TRACE("(%p)->(%s %lx)\n", This, debugstr_w(pstrName), dwFlags);
- if(This->thread_id != GetCurrentThreadId() || !This->ctx || This->ctx->state == SCRIPTSTATE_CLOSED) + if(!This->thread_data || This->thread_data->thread_id != GetCurrentThreadId() || !This->ctx || This->ctx->state == SCRIPTSTATE_CLOSED) return E_UNEXPECTED;
if(dwFlags & SCRIPTITEM_GLOBALMEMBERS) { @@ -959,7 +969,7 @@ static HRESULT WINAPI JScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR if(!ppdisp) return E_POINTER;
- if(This->thread_id != GetCurrentThreadId() || !This->ctx->global) { + if(!This->thread_data || This->thread_data->thread_id != GetCurrentThreadId() || !This->ctx->global) { *ppdisp = NULL; return E_UNEXPECTED; } @@ -1101,7 +1111,7 @@ static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface, debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter), wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLine, dwFlags, pvarResult, pexcepinfo);
- if(This->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED) + if(!This->thread_data || This->thread_data->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED) return E_UNEXPECTED;
if(pstrItemName) { @@ -1204,7 +1214,7 @@ static HRESULT WINAPI JScriptParseProcedure_ParseProcedureText(IActiveScriptPars debugstr_w(pstrProcedureName), debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter), wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLineNumber, dwFlags, ppdisp);
- if(This->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED) + if(!This->thread_data || This->thread_data->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED) return E_UNEXPECTED;
if(pstrItemName) { diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 650c9278793..0e4f97b085d 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -129,6 +129,14 @@ typedef HRESULT (*builtin_setter_t)(script_ctx_t*,jsdisp_t*,jsval_t);
HRESULT builtin_set_const(script_ctx_t*,jsdisp_t*,jsval_t);
+struct thread_data { + LONG ref; + LONG thread_id; +}; + +struct thread_data *get_thread_data(void); +void release_thread_data(struct thread_data*); + typedef struct named_item_t { jsdisp_t *script_obj; IDispatch *disp; diff --git a/dlls/jscript/jscript_main.c b/dlls/jscript/jscript_main.c index 882c419ff83..2afe6fb2ff7 100644 --- a/dlls/jscript/jscript_main.c +++ b/dlls/jscript/jscript_main.c @@ -37,8 +37,34 @@ LONG module_ref = 0; DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
HINSTANCE jscript_hinstance; +static DWORD jscript_tls; static ITypeInfo *dispatch_typeinfo;
+struct thread_data *get_thread_data(void) +{ + struct thread_data *thread_data = TlsGetValue(jscript_tls); + + if(!thread_data) { + thread_data = calloc(1, sizeof(struct thread_data)); + if(!thread_data) + return NULL; + thread_data->thread_id = GetCurrentThreadId(); + TlsSetValue(jscript_tls, thread_data); + } + + thread_data->ref++; + return thread_data; +} + +void release_thread_data(struct thread_data *thread_data) +{ + if(--thread_data->ref) + return; + + free(thread_data); + TlsSetValue(jscript_tls, NULL); +} + HRESULT get_dispatch_typeinfo(ITypeInfo **out) { ITypeInfo *typeinfo; @@ -164,13 +190,16 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hInstDLL); jscript_hinstance = hInstDLL; - if(!init_strings()) + jscript_tls = TlsAlloc(); + if(jscript_tls == TLS_OUT_OF_INDEXES || !init_strings()) return FALSE; break; case DLL_PROCESS_DETACH: if (lpv) break; if (dispatch_typeinfo) ITypeInfo_Release(dispatch_typeinfo); + if(jscript_tls != TLS_OUT_OF_INDEXES) TlsFree(jscript_tls); free_strings(); + break; }
return TRUE;
From: Gabriel Ivăncescu gabrielopcode@gmail.com
It already bails out early if the thread_data was already populated, so only one thread can reach here at one time.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/jscript.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index 191747c7173..32e6278a5d0 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -776,11 +776,7 @@ static HRESULT WINAPI JScript_SetScriptSite(IActiveScript *iface,
ctx->last_match = jsstr_empty();
- ctx = InterlockedCompareExchangePointer((void**)&This->ctx, ctx, NULL); - if(ctx) { - script_release(ctx); - return E_UNEXPECTED; - } + This->ctx = ctx; }
/* Retrieve new dispatches for persistent named items */
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 31 ++++++++++++++++--------------- dlls/jscript/jscript.c | 12 +++--------- dlls/jscript/jscript.h | 12 +++++++----- dlls/jscript/jscript_main.c | 9 +++++++++ dlls/jscript/set.c | 6 +++--- 5 files changed, 38 insertions(+), 32 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index ef72860f627..88c63811386 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -783,6 +783,7 @@ HRESULT gc_run(script_ctx_t *ctx) struct chunk *next; LONG ref[1020]; } *head, *chunk; + struct thread_data *thread_data = ctx->thread_data; jsdisp_t *obj, *obj2, *link, *link2; dispex_prop_t *prop, *props_end; struct gc_ctx gc_ctx = { 0 }; @@ -791,7 +792,7 @@ HRESULT gc_run(script_ctx_t *ctx) struct list *iter;
/* Prevent recursive calls from side-effects during unlinking (e.g. CollectGarbage from host object's Release) */ - if(ctx->gc_is_unlinking) + if(thread_data->gc_is_unlinking) return S_OK;
if(!(head = malloc(sizeof(*head)))) @@ -800,7 +801,7 @@ HRESULT gc_run(script_ctx_t *ctx) chunk = head;
/* 1. Save actual refcounts and decrease them speculatively as-if we unlinked the objects */ - LIST_FOR_EACH_ENTRY(obj, &ctx->objects, jsdisp_t, entry) { + LIST_FOR_EACH_ENTRY(obj, &thread_data->objects, jsdisp_t, entry) { if(chunk_idx == ARRAY_SIZE(chunk->ref)) { if(!(chunk->next = malloc(sizeof(*chunk)))) { do { @@ -815,7 +816,7 @@ HRESULT gc_run(script_ctx_t *ctx) } chunk->ref[chunk_idx++] = obj->ref; } - LIST_FOR_EACH_ENTRY(obj, &ctx->objects, jsdisp_t, entry) { + LIST_FOR_EACH_ENTRY(obj, &thread_data->objects, jsdisp_t, entry) { for(prop = obj->props, props_end = prop + obj->prop_cnt; prop < props_end; prop++) { switch(prop->type) { case PROP_JSVAL: @@ -841,7 +842,7 @@ HRESULT gc_run(script_ctx_t *ctx) }
/* 2. Clear mark on objects with non-zero "external refcount" and all objects accessible from them */ - LIST_FOR_EACH_ENTRY(obj, &ctx->objects, jsdisp_t, entry) { + LIST_FOR_EACH_ENTRY(obj, &thread_data->objects, jsdisp_t, entry) { if(!obj->ref || !obj->gc_marked) continue;
@@ -899,7 +900,7 @@ HRESULT gc_run(script_ctx_t *ctx) /* For weak refs, traverse paths accessible from it via the WeakMaps, if the WeakMaps are alive at this point. We need both the key and the WeakMap for the entry to actually be accessible (and thus traversed). */ if(obj2->has_weak_refs) { - struct list *list = &RB_ENTRY_VALUE(rb_get(&ctx->weak_refs, obj2), struct weak_refs_entry, entry)->list; + struct list *list = &RB_ENTRY_VALUE(rb_get(&thread_data->weak_refs, obj2), struct weak_refs_entry, entry)->list; struct weakmap_entry *entry;
LIST_FOR_EACH_ENTRY(entry, list, struct weakmap_entry, weak_refs_entry) { @@ -926,7 +927,7 @@ HRESULT gc_run(script_ctx_t *ctx)
/* Restore */ chunk = head; chunk_idx = 0; - LIST_FOR_EACH_ENTRY(obj, &ctx->objects, jsdisp_t, entry) { + LIST_FOR_EACH_ENTRY(obj, &thread_data->objects, jsdisp_t, entry) { obj->ref = chunk->ref[chunk_idx++]; if(chunk_idx == ARRAY_SIZE(chunk->ref)) { struct chunk *next = chunk->next; @@ -940,13 +941,13 @@ HRESULT gc_run(script_ctx_t *ctx) return hres;
/* 3. Remove all the links from the marked objects, since they are dangling */ - ctx->gc_is_unlinking = TRUE; + thread_data->gc_is_unlinking = TRUE;
- iter = list_head(&ctx->objects); + iter = list_head(&thread_data->objects); while(iter) { obj = LIST_ENTRY(iter, jsdisp_t, entry); if(!obj->gc_marked) { - iter = list_next(&ctx->objects, iter); + iter = list_next(&thread_data->objects, iter); continue; }
@@ -956,12 +957,12 @@ HRESULT gc_run(script_ctx_t *ctx)
/* Releasing unlinked object should not delete any other object, so we can safely obtain the next pointer now */ - iter = list_next(&ctx->objects, iter); + iter = list_next(&thread_data->objects, iter); jsdisp_release(obj); }
- ctx->gc_is_unlinking = FALSE; - ctx->gc_last_tick = GetTickCount(); + thread_data->gc_is_unlinking = FALSE; + thread_data->gc_last_tick = GetTickCount(); return S_OK; }
@@ -2174,7 +2175,7 @@ HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *b unsigned i;
/* FIXME: Use better heuristics to decide when to run the GC */ - if(GetTickCount() - ctx->gc_last_tick > 30000) + if(GetTickCount() - ctx->thread_data->gc_last_tick > 30000) gc_run(ctx);
TRACE("%p (%p)\n", dispex, prototype); @@ -2201,7 +2202,7 @@ HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *b script_addref(ctx); dispex->ctx = ctx;
- list_add_tail(&ctx->objects, &dispex->entry); + list_add_tail(&ctx->thread_data->objects, &dispex->entry); return S_OK; }
@@ -2241,7 +2242,7 @@ void jsdisp_free(jsdisp_t *obj) TRACE("(%p)\n", obj);
if(obj->has_weak_refs) { - struct list *list = &RB_ENTRY_VALUE(rb_get(&obj->ctx->weak_refs, obj), struct weak_refs_entry, entry)->list; + struct list *list = &RB_ENTRY_VALUE(rb_get(&obj->ctx->thread_data->weak_refs, obj), struct weak_refs_entry, entry)->list; do { remove_weakmap_entry(LIST_ENTRY(list->next, struct weakmap_entry, weak_refs_entry)); } while(obj->has_weak_refs); diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index 32e6278a5d0..6829f80f299 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -88,6 +88,7 @@ void script_release(script_ctx_t *ctx) ctx->jscaller->ctx = NULL; IServiceProvider_Release(&ctx->jscaller->IServiceProvider_iface);
+ release_thread_data(ctx->thread_data); free(ctx); }
@@ -719,13 +720,6 @@ static ULONG WINAPI JScript_Release(IActiveScript *iface) return ref; }
-static int weak_refs_compare(const void *key, const struct rb_entry *entry) -{ - const struct weak_refs_entry *weak_refs_entry = RB_ENTRY_VALUE(entry, const struct weak_refs_entry, entry); - ULONG_PTR a = (ULONG_PTR)key, b = (ULONG_PTR)LIST_ENTRY(weak_refs_entry->list.next, struct weakmap_entry, weak_refs_entry)->key; - return (a > b) - (a < b); -} - static HRESULT WINAPI JScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass) { @@ -764,8 +758,6 @@ static HRESULT WINAPI JScript_SetScriptSite(IActiveScript *iface, ctx->html_mode = This->html_mode; ctx->acc = jsval_undefined(); list_init(&ctx->named_items); - list_init(&ctx->objects); - rb_init(&ctx->weak_refs, weak_refs_compare); heap_pool_init(&ctx->tmp_heap);
hres = create_jscaller(ctx); @@ -774,6 +766,8 @@ static HRESULT WINAPI JScript_SetScriptSite(IActiveScript *iface, return hres; }
+ thread_data->ref++; + ctx->thread_data = thread_data; ctx->last_match = jsstr_empty();
This->ctx = ctx; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 0e4f97b085d..b62d577a45b 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -132,6 +132,12 @@ HRESULT builtin_set_const(script_ctx_t*,jsdisp_t*,jsval_t); struct thread_data { LONG ref; LONG thread_id; + + BOOL gc_is_unlinking; + DWORD gc_last_tick; + + struct list objects; + struct rb_tree weak_refs; };
struct thread_data *get_thread_data(void); @@ -383,10 +389,9 @@ struct _script_ctx_t { SCRIPTSTATE state; IActiveScript *active_script;
+ struct thread_data *thread_data; struct _call_frame_t *call_ctx; struct list named_items; - struct list objects; - struct rb_tree weak_refs; IActiveScriptSite *site; IInternetHostSecurityManager *secmgr; DWORD safeopt; @@ -399,9 +404,6 @@ struct _script_ctx_t {
heap_pool_t tmp_heap;
- BOOL gc_is_unlinking; - DWORD gc_last_tick; - jsval_t *stack; unsigned stack_top; jsval_t acc; diff --git a/dlls/jscript/jscript_main.c b/dlls/jscript/jscript_main.c index 2afe6fb2ff7..ecbb5a713ab 100644 --- a/dlls/jscript/jscript_main.c +++ b/dlls/jscript/jscript_main.c @@ -40,6 +40,13 @@ HINSTANCE jscript_hinstance; static DWORD jscript_tls; static ITypeInfo *dispatch_typeinfo;
+static int weak_refs_compare(const void *key, const struct rb_entry *entry) +{ + const struct weak_refs_entry *weak_refs_entry = RB_ENTRY_VALUE(entry, const struct weak_refs_entry, entry); + ULONG_PTR a = (ULONG_PTR)key, b = (ULONG_PTR)LIST_ENTRY(weak_refs_entry->list.next, struct weakmap_entry, weak_refs_entry)->key; + return (a > b) - (a < b); +} + struct thread_data *get_thread_data(void) { struct thread_data *thread_data = TlsGetValue(jscript_tls); @@ -49,6 +56,8 @@ struct thread_data *get_thread_data(void) if(!thread_data) return NULL; thread_data->thread_id = GetCurrentThreadId(); + list_init(&thread_data->objects); + rb_init(&thread_data->weak_refs, weak_refs_compare); TlsSetValue(jscript_tls, thread_data); }
diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index ac9efbb4da0..bf2045c7c41 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -658,7 +658,7 @@ void remove_weakmap_entry(struct weakmap_entry *entry) else { struct weak_refs_entry *weak_refs_entry = LIST_ENTRY(next, struct weak_refs_entry, list); entry->key->has_weak_refs = FALSE; - rb_remove(&entry->key->ctx->weak_refs, &weak_refs_entry->entry); + rb_remove(&entry->key->ctx->thread_data->weak_refs, &weak_refs_entry->entry); free(weak_refs_entry); } rb_remove(&weakmap->map, &entry->entry); @@ -771,14 +771,14 @@ static HRESULT WeakMap_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigne }
if(key->has_weak_refs) - weak_refs_entry = RB_ENTRY_VALUE(rb_get(&ctx->weak_refs, key), struct weak_refs_entry, entry); + weak_refs_entry = RB_ENTRY_VALUE(rb_get(&ctx->thread_data->weak_refs, key), struct weak_refs_entry, entry); else { if(!(weak_refs_entry = malloc(sizeof(*weak_refs_entry)))) { jsval_release(entry->value); free(entry); return E_OUTOFMEMORY; } - rb_put(&ctx->weak_refs, key, &weak_refs_entry->entry); + rb_put(&ctx->thread_data->weak_refs, key, &weak_refs_entry->entry); list_init(&weak_refs_entry->list); key->has_weak_refs = TRUE; }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 18 +++++----- dlls/jscript/set.c | 5 --- dlls/jscript/tests/run.c | 75 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 82 insertions(+), 16 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 88c63811386..57882bf499e 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -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++) { switch(prop->type) { 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--; break; case PROP_ACCESSOR: - if(prop->u.accessor.getter && prop->u.accessor.getter->ctx == ctx) + if(prop->u.accessor.getter) 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--; break; 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--; if(obj->builtin_info->gc_traverse) obj->builtin_info->gc_traverse(&gc_ctx, GC_TRAVERSE_SPECULATIVELY, obj); @@ -870,12 +870,12 @@ HRESULT gc_run(script_ctx_t *ctx) default: continue; } - if(link && link->gc_marked && link->ctx == ctx) { + if(link && link->gc_marked) { hres = gc_stack_push(&gc_ctx, link); if(FAILED(hres)) break; } - if(link2 && link2->gc_marked && link2->ctx == ctx) { + if(link2 && link2->gc_marked) { hres = gc_stack_push(&gc_ctx, link2); if(FAILED(hres)) break; @@ -885,7 +885,7 @@ HRESULT gc_run(script_ctx_t *ctx) if(FAILED(hres)) 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); if(FAILED(hres)) break; @@ -974,8 +974,6 @@ HRESULT gc_process_linked_obj(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsd return S_OK; }
- if(link->ctx != obj->ctx) - return S_OK; if(op == GC_TRAVERSE_SPECULATIVELY) link->ref--; 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; }
- 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; if(op == GC_TRAVERSE_SPECULATIVELY) jsdisp->ref--; diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index bf2045c7c41..7e49e31a5d5 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -745,11 +745,6 @@ static HRESULT WeakMap_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigne if(!key) 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))) { jsval_t val; hres = jsval_copy(value, &val); diff --git a/dlls/jscript/tests/run.c b/dlls/jscript/tests/run.c index 509f01e3211..db1e95dc844 100644 --- a/dlls/jscript/tests/run.c +++ b/dlls/jscript/tests/run.c @@ -3596,9 +3596,14 @@ static void test_destructors(void) "a.ref = { 'ref': Math, 'a': a }; b.ref = Math.ref;\n" "a.self = a; b.self = b; c.self = c;\n" "})(), true"; + static DISPID propput_dispid = DISPID_PROPERTYPUT; + IActiveScript *script, *script2; + IDispatchEx *dispex, *dispex2; IActiveScriptParse *parser; - IActiveScript *script; + DISPPARAMS dp = { 0 }; VARIANT v; + DISPID id; + BSTR str; HRESULT hres;
V_VT(&v) = VT_EMPTY; @@ -3643,6 +3648,74 @@ static void test_destructors(void) CHECK_CALLED(testdestrobj);
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)
Looks go to me now (after code freeze).
This merge request was approved by Jacek Caban.