@@ -341,6 +341,7 @@ typedef enum {
341
341
JS_GC_OBJ_TYPE_VAR_REF,
342
342
JS_GC_OBJ_TYPE_ASYNC_FUNCTION,
343
343
JS_GC_OBJ_TYPE_JS_CONTEXT,
344
+ JS_GC_OBJ_TYPE_MODULE,
344
345
} JSGCObjectTypeEnum;
345
346
346
347
/* header for GC objects. GC objects are C data structures with a
@@ -805,7 +806,7 @@ typedef enum {
805
806
} JSModuleStatus;
806
807
807
808
struct JSModuleDef {
808
- JSRefCountHeader header; /* must come first, 32-bit */
809
+ JSGCObjectHeader header; /* must come first */
809
810
JSAtom module_name;
810
811
struct list_head link;
811
812
@@ -857,7 +858,7 @@ struct JSModuleDef {
857
858
858
859
typedef struct JSJobEntry {
859
860
struct list_head link;
860
- JSContext *ctx ;
861
+ JSContext *realm ;
861
862
JSJobFunc *job_func;
862
863
int argc;
863
864
JSValue argv[0];
@@ -1222,7 +1223,7 @@ static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
1222
1223
static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
1223
1224
const char *input, size_t input_len,
1224
1225
const char *filename, int flags, int scope_idx);
1225
- static void js_free_module_def(JSContext *ctx , JSModuleDef *m);
1226
+ static void js_free_module_def(JSRuntime *rt , JSModuleDef *m);
1226
1227
static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
1227
1228
JS_MarkFunc *mark_func);
1228
1229
static JSValue js_import_meta(JSContext *ctx);
@@ -1782,7 +1783,7 @@ int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func,
1782
1783
e = js_malloc(ctx, sizeof(*e) + argc * sizeof(JSValue));
1783
1784
if (!e)
1784
1785
return -1;
1785
- e->ctx = ctx;
1786
+ e->realm = JS_DupContext( ctx) ;
1786
1787
e->job_func = job_func;
1787
1788
e->argc = argc;
1788
1789
for(i = 0; i < argc; i++) {
@@ -1798,7 +1799,10 @@ BOOL JS_IsJobPending(JSRuntime *rt)
1798
1799
}
1799
1800
1800
1801
/* return < 0 if exception, 0 if no job pending, 1 if a job was
1801
- executed successfully. the context of the job is stored in '*pctx' */
1802
+ executed successfully. The context of the job is stored in '*pctx'
1803
+ if pctx != NULL. It may be NULL if the context was already
1804
+ destroyed or if no job was pending. The 'pctx' parameter is now
1805
+ absolete. */
1802
1806
int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx)
1803
1807
{
1804
1808
JSContext *ctx;
@@ -1807,15 +1811,16 @@ int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx)
1807
1811
int i, ret;
1808
1812
1809
1813
if (list_empty(&rt->job_list)) {
1810
- *pctx = NULL;
1814
+ if (pctx)
1815
+ *pctx = NULL;
1811
1816
return 0;
1812
1817
}
1813
1818
1814
1819
/* get the first pending job and execute it */
1815
1820
e = list_entry(rt->job_list.next, JSJobEntry, link);
1816
1821
list_del(&e->link);
1817
- ctx = e->ctx ;
1818
- res = e->job_func(e-> ctx, e->argc, (JSValueConst *)e->argv);
1822
+ ctx = e->realm ;
1823
+ res = e->job_func(ctx, e->argc, (JSValueConst *)e->argv);
1819
1824
for(i = 0; i < e->argc; i++)
1820
1825
JS_FreeValue(ctx, e->argv[i]);
1821
1826
if (JS_IsException(res))
@@ -1824,7 +1829,13 @@ int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx)
1824
1829
ret = 1;
1825
1830
JS_FreeValue(ctx, res);
1826
1831
js_free(ctx, e);
1827
- *pctx = ctx;
1832
+ if (pctx) {
1833
+ if (ctx->header.ref_count > 1)
1834
+ *pctx = ctx;
1835
+ else
1836
+ *pctx = NULL;
1837
+ }
1838
+ JS_FreeContext(ctx);
1828
1839
return ret;
1829
1840
}
1830
1841
@@ -1905,6 +1916,7 @@ void JS_FreeRuntime(JSRuntime *rt)
1905
1916
JSJobEntry *e = list_entry(el, JSJobEntry, link);
1906
1917
for(i = 0; i < e->argc; i++)
1907
1918
JS_FreeValueRT(rt, e->argv[i]);
1919
+ JS_FreeContext(e->realm);
1908
1920
js_free_rt(rt, e);
1909
1921
}
1910
1922
init_list_head(&rt->job_list);
@@ -2180,7 +2192,13 @@ static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag)
2180
2192
JSModuleDef *m = list_entry(el, JSModuleDef, link);
2181
2193
if (flag == JS_FREE_MODULE_ALL ||
2182
2194
(flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved)) {
2183
- js_free_module_def(ctx, m);
2195
+ /* warning: the module may be referenced elsewhere. It
2196
+ could be simpler to use an array instead of a list for
2197
+ 'ctx->loaded_modules' */
2198
+ list_del(&m->link);
2199
+ m->link.prev = NULL;
2200
+ m->link.next = NULL;
2201
+ JS_FreeValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
2184
2202
}
2185
2203
}
2186
2204
}
@@ -2198,11 +2216,9 @@ static void JS_MarkContext(JSRuntime *rt, JSContext *ctx,
2198
2216
int i;
2199
2217
struct list_head *el;
2200
2218
2201
- /* modules are not seen by the GC, so we directly mark the objects
2202
- referenced by each module */
2203
2219
list_for_each(el, &ctx->loaded_modules) {
2204
2220
JSModuleDef *m = list_entry(el, JSModuleDef, link);
2205
- js_mark_module_def (rt, m , mark_func);
2221
+ JS_MarkValue (rt, JS_MKPTR(JS_TAG_MODULE, m) , mark_func);
2206
2222
}
2207
2223
2208
2224
JS_MarkValue(rt, ctx->global_obj, mark_func);
@@ -5783,6 +5799,9 @@ static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp)
5783
5799
case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
5784
5800
__async_func_free(rt, (JSAsyncFunctionState *)gp);
5785
5801
break;
5802
+ case JS_GC_OBJ_TYPE_MODULE:
5803
+ js_free_module_def(rt, (JSModuleDef *)gp);
5804
+ break;
5786
5805
default:
5787
5806
abort();
5788
5807
}
@@ -5847,6 +5866,7 @@ void __JS_FreeValueRT(JSRuntime *rt, JSValue v)
5847
5866
break;
5848
5867
case JS_TAG_OBJECT:
5849
5868
case JS_TAG_FUNCTION_BYTECODE:
5869
+ case JS_TAG_MODULE:
5850
5870
{
5851
5871
JSGCObjectHeader *p = JS_VALUE_GET_PTR(v);
5852
5872
if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
@@ -5859,9 +5879,6 @@ void __JS_FreeValueRT(JSRuntime *rt, JSValue v)
5859
5879
}
5860
5880
}
5861
5881
break;
5862
- case JS_TAG_MODULE:
5863
- abort(); /* never freed here */
5864
- break;
5865
5882
case JS_TAG_BIG_INT:
5866
5883
{
5867
5884
JSBigInt *p = JS_VALUE_GET_PTR(v);
@@ -5935,6 +5952,7 @@ void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
5935
5952
switch(JS_VALUE_GET_TAG(val)) {
5936
5953
case JS_TAG_OBJECT:
5937
5954
case JS_TAG_FUNCTION_BYTECODE:
5955
+ case JS_TAG_MODULE:
5938
5956
mark_func(rt, JS_VALUE_GET_PTR(val));
5939
5957
break;
5940
5958
default:
@@ -6047,6 +6065,12 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,
6047
6065
JS_MarkContext(rt, ctx, mark_func);
6048
6066
}
6049
6067
break;
6068
+ case JS_GC_OBJ_TYPE_MODULE:
6069
+ {
6070
+ JSModuleDef *m = (JSModuleDef *)gp;
6071
+ js_mark_module_def(rt, m, mark_func);
6072
+ }
6073
+ break;
6050
6074
default:
6051
6075
abort();
6052
6076
}
@@ -6143,6 +6167,7 @@ static void gc_free_cycles(JSRuntime *rt)
6143
6167
case JS_GC_OBJ_TYPE_JS_OBJECT:
6144
6168
case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
6145
6169
case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
6170
+ case JS_GC_OBJ_TYPE_MODULE:
6146
6171
#ifdef DUMP_GC_FREE
6147
6172
if (!header_done) {
6148
6173
printf("Freeing cycles:\n");
@@ -6165,7 +6190,8 @@ static void gc_free_cycles(JSRuntime *rt)
6165
6190
p = list_entry(el, JSGCObjectHeader, link);
6166
6191
assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT ||
6167
6192
p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE ||
6168
- p->gc_obj_type == JS_GC_OBJ_TYPE_ASYNC_FUNCTION);
6193
+ p->gc_obj_type == JS_GC_OBJ_TYPE_ASYNC_FUNCTION ||
6194
+ p->gc_obj_type == JS_GC_OBJ_TYPE_MODULE);
6169
6195
if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT &&
6170
6196
((JSObject *)p)->weakref_count != 0) {
6171
6197
/* keep the object because there are weak references to it */
@@ -13747,6 +13773,9 @@ static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p)
13747
13773
case JS_GC_OBJ_TYPE_JS_CONTEXT:
13748
13774
printf("[js_context]");
13749
13775
break;
13776
+ case JS_GC_OBJ_TYPE_MODULE:
13777
+ printf("[module]");
13778
+ break;
13750
13779
default:
13751
13780
printf("[unknown %d]", p->gc_obj_type);
13752
13781
break;
@@ -28216,7 +28245,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
28216
28245
return -1;
28217
28246
}
28218
28247
28219
- /* 'name' is freed */
28248
+ /* 'name' is freed. The module is referenced by 'ctx->loaded_modules' */
28220
28249
static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name)
28221
28250
{
28222
28251
JSModuleDef *m;
@@ -28226,6 +28255,7 @@ static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name)
28226
28255
return NULL;
28227
28256
}
28228
28257
m->header.ref_count = 1;
28258
+ add_gc_object(ctx->rt, &m->header, JS_GC_OBJ_TYPE_MODULE);
28229
28259
m->module_name = name;
28230
28260
m->module_ns = JS_UNDEFINED;
28231
28261
m->func_obj = JS_UNDEFINED;
@@ -28267,47 +28297,56 @@ static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
28267
28297
JS_MarkValue(rt, m->private_value, mark_func);
28268
28298
}
28269
28299
28270
- static void js_free_module_def(JSContext *ctx , JSModuleDef *m)
28300
+ static void js_free_module_def(JSRuntime *rt , JSModuleDef *m)
28271
28301
{
28272
28302
int i;
28273
28303
28274
- JS_FreeAtom(ctx , m->module_name);
28304
+ JS_FreeAtomRT(rt , m->module_name);
28275
28305
28276
28306
for(i = 0; i < m->req_module_entries_count; i++) {
28277
28307
JSReqModuleEntry *rme = &m->req_module_entries[i];
28278
- JS_FreeAtom(ctx , rme->module_name);
28279
- JS_FreeValue(ctx , rme->attributes);
28308
+ JS_FreeAtomRT(rt , rme->module_name);
28309
+ JS_FreeValueRT(rt , rme->attributes);
28280
28310
}
28281
- js_free(ctx , m->req_module_entries);
28311
+ js_free_rt(rt , m->req_module_entries);
28282
28312
28283
28313
for(i = 0; i < m->export_entries_count; i++) {
28284
28314
JSExportEntry *me = &m->export_entries[i];
28285
28315
if (me->export_type == JS_EXPORT_TYPE_LOCAL)
28286
- free_var_ref(ctx-> rt, me->u.local.var_ref);
28287
- JS_FreeAtom(ctx , me->export_name);
28288
- JS_FreeAtom(ctx , me->local_name);
28316
+ free_var_ref(rt, me->u.local.var_ref);
28317
+ JS_FreeAtomRT(rt , me->export_name);
28318
+ JS_FreeAtomRT(rt , me->local_name);
28289
28319
}
28290
- js_free(ctx , m->export_entries);
28320
+ js_free_rt(rt , m->export_entries);
28291
28321
28292
- js_free(ctx , m->star_export_entries);
28322
+ js_free_rt(rt , m->star_export_entries);
28293
28323
28294
28324
for(i = 0; i < m->import_entries_count; i++) {
28295
28325
JSImportEntry *mi = &m->import_entries[i];
28296
- JS_FreeAtom(ctx , mi->import_name);
28326
+ JS_FreeAtomRT(rt , mi->import_name);
28297
28327
}
28298
- js_free(ctx , m->import_entries);
28299
- js_free(ctx , m->async_parent_modules);
28328
+ js_free_rt(rt , m->import_entries);
28329
+ js_free_rt(rt , m->async_parent_modules);
28300
28330
28301
- JS_FreeValue(ctx, m->module_ns);
28302
- JS_FreeValue(ctx, m->func_obj);
28303
- JS_FreeValue(ctx, m->eval_exception);
28304
- JS_FreeValue(ctx, m->meta_obj);
28305
- JS_FreeValue(ctx, m->promise);
28306
- JS_FreeValue(ctx, m->resolving_funcs[0]);
28307
- JS_FreeValue(ctx, m->resolving_funcs[1]);
28308
- JS_FreeValue(ctx, m->private_value);
28309
- list_del(&m->link);
28310
- js_free(ctx, m);
28331
+ JS_FreeValueRT(rt, m->module_ns);
28332
+ JS_FreeValueRT(rt, m->func_obj);
28333
+ JS_FreeValueRT(rt, m->eval_exception);
28334
+ JS_FreeValueRT(rt, m->meta_obj);
28335
+ JS_FreeValueRT(rt, m->promise);
28336
+ JS_FreeValueRT(rt, m->resolving_funcs[0]);
28337
+ JS_FreeValueRT(rt, m->resolving_funcs[1]);
28338
+ JS_FreeValueRT(rt, m->private_value);
28339
+ /* during the GC the finalizers are called in an arbitrary
28340
+ order so the module may no longer be referenced by the JSContext list */
28341
+ if (m->link.next) {
28342
+ list_del(&m->link);
28343
+ }
28344
+ remove_gc_object(&m->header);
28345
+ if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && m->header.ref_count != 0) {
28346
+ list_add_tail(&m->header.link, &rt->gc_zero_ref_count_list);
28347
+ } else {
28348
+ js_free_rt(rt, m);
28349
+ }
28311
28350
}
28312
28351
28313
28352
static int add_req_module_entry(JSContext *ctx, JSModuleDef *m,
@@ -35804,7 +35843,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
35804
35843
fail1:
35805
35844
/* XXX: should free all the unresolved dependencies */
35806
35845
if (m)
35807
- js_free_module_def (ctx, m );
35846
+ JS_FreeValue (ctx, JS_MKPTR(JS_TAG_MODULE, m) );
35808
35847
return JS_EXCEPTION;
35809
35848
}
35810
35849
@@ -37516,7 +37555,7 @@ static JSValue JS_ReadModule(BCReaderState *s)
37516
37555
return obj;
37517
37556
fail:
37518
37557
if (m) {
37519
- js_free_module_def (ctx, m );
37558
+ JS_FreeValue (ctx, JS_MKPTR(JS_TAG_MODULE, m) );
37520
37559
}
37521
37560
return JS_EXCEPTION;
37522
37561
}
@@ -55663,7 +55702,7 @@ typedef struct JSFinRecEntry {
55663
55702
typedef struct JSFinalizationRegistryData {
55664
55703
JSWeakRefHeader weakref_header;
55665
55704
struct list_head entries; /* list of JSFinRecEntry.link */
55666
- JSContext *ctx ;
55705
+ JSContext *realm ;
55667
55706
JSValue cb;
55668
55707
} JSFinalizationRegistryData;
55669
55708
@@ -55680,6 +55719,7 @@ static void js_finrec_finalizer(JSRuntime *rt, JSValue val)
55680
55719
js_free_rt(rt, fre);
55681
55720
}
55682
55721
JS_FreeValueRT(rt, frd->cb);
55722
+ JS_FreeContext(frd->realm);
55683
55723
list_del(&frd->weakref_header.link);
55684
55724
js_free_rt(rt, frd);
55685
55725
}
@@ -55696,6 +55736,7 @@ static void js_finrec_mark(JSRuntime *rt, JSValueConst val,
55696
55736
JS_MarkValue(rt, fre->held_val, mark_func);
55697
55737
}
55698
55738
JS_MarkValue(rt, frd->cb, mark_func);
55739
+ mark_func(rt, &frd->realm->header);
55699
55740
}
55700
55741
}
55701
55742
@@ -55721,7 +55762,7 @@ static void finrec_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh)
55721
55762
JSValueConst args[2];
55722
55763
args[0] = frd->cb;
55723
55764
args[1] = fre->held_val;
55724
- JS_EnqueueJob(frd->ctx , js_finrec_job, 2, args);
55765
+ JS_EnqueueJob(frd->realm , js_finrec_job, 2, args);
55725
55766
55726
55767
js_weakref_free(rt, fre->target);
55727
55768
js_weakref_free(rt, fre->token);
@@ -55756,7 +55797,7 @@ static JSValue js_finrec_constructor(JSContext *ctx, JSValueConst new_target,
55756
55797
frd->weakref_header.weakref_type = JS_WEAKREF_TYPE_FINREC;
55757
55798
list_add_tail(&frd->weakref_header.link, &ctx->rt->weakref_list);
55758
55799
init_list_head(&frd->entries);
55759
- frd->ctx = ctx; /* XXX: JS_DupContext() ? */
55800
+ frd->realm = JS_DupContext(ctx);
55760
55801
frd->cb = JS_DupValue(ctx, cb);
55761
55802
JS_SetOpaque(obj, frd);
55762
55803
return obj;
0 commit comments