quickjs 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -57,6 +57,16 @@ typedef struct VMData
57
57
  VALUE log_listener;
58
58
  VALUE alive_objects;
59
59
  VALUE module_loader;
60
+ VALUE on_unhandled_rejection;
61
+ // Memoize (specifier, importer) → canonical so the user's loader Proc
62
+ // runs at most once per distinct pair across the VM's lifetime. Without
63
+ // this, QuickJS calls normalize on every import statement — including
64
+ // duplicates within the same file — and we'd re-invoke the user proc.
65
+ VALUE module_resolution_cache;
66
+ // Carries `code` from the normalize-phase Proc call to the load-phase
67
+ // JS_Eval that follows. Keyed by canonical; populated when the user's
68
+ // loader returns either a raw source String or `{ code:, as: }`.
69
+ VALUE module_source_cache;
60
70
  JSValue j_file_proxy_creator;
61
71
  // Once the runtime has hit JS-level "out of memory", the QuickJS heap is in
62
72
  // a fragile state where further evaluation can trigger a use-after-free in
@@ -64,21 +74,33 @@ typedef struct VMData
64
74
  // Trip this flag so subsequent eval_code/call calls refuse cleanly with a
65
75
  // Ruby exception instead of risking a process crash.
66
76
  bool oom_poisoned;
77
+ // Set by VM#dispose! to release the multi-MB JS heap before Ruby GC sees
78
+ // enough pressure to collect the wrapper. Doubles as a double-free guard
79
+ // for the dfree handler.
80
+ bool disposed;
67
81
  } VMData;
68
82
 
83
+ static void vm_teardown_context(JSContext *ctx)
84
+ {
85
+ JSRuntime *runtime = JS_GetRuntime(ctx);
86
+ JS_SetInterruptHandler(runtime, NULL, NULL);
87
+ js_std_free_handlers(runtime);
88
+ JS_FreeContext(ctx);
89
+ JS_FreeRuntime(runtime);
90
+ }
91
+
69
92
  static void vm_free(void *ptr)
70
93
  {
71
94
  VMData *data = (VMData *)ptr;
72
95
  free(data->eval_time);
73
96
 
74
- if (!JS_IsUndefined(data->j_file_proxy_creator))
75
- JS_FreeValue(data->context, data->j_file_proxy_creator);
97
+ if (!data->disposed)
98
+ {
99
+ if (!JS_IsUndefined(data->j_file_proxy_creator))
100
+ JS_FreeValue(data->context, data->j_file_proxy_creator);
76
101
 
77
- JSRuntime *runtime = JS_GetRuntime(data->context);
78
- JS_SetInterruptHandler(runtime, NULL, NULL);
79
- js_std_free_handlers(runtime);
80
- JS_FreeContext(data->context);
81
- JS_FreeRuntime(runtime);
102
+ vm_teardown_context(data->context);
103
+ }
82
104
 
83
105
  xfree(ptr);
84
106
  }
@@ -95,6 +117,9 @@ static void vm_mark(void *ptr)
95
117
  rb_gc_mark_movable(data->log_listener);
96
118
  rb_gc_mark_movable(data->alive_objects);
97
119
  rb_gc_mark_movable(data->module_loader);
120
+ rb_gc_mark_movable(data->on_unhandled_rejection);
121
+ rb_gc_mark_movable(data->module_resolution_cache);
122
+ rb_gc_mark_movable(data->module_source_cache);
98
123
  }
99
124
 
100
125
  static void vm_compact(void *ptr)
@@ -104,6 +129,9 @@ static void vm_compact(void *ptr)
104
129
  data->log_listener = rb_gc_location(data->log_listener);
105
130
  data->alive_objects = rb_gc_location(data->alive_objects);
106
131
  data->module_loader = rb_gc_location(data->module_loader);
132
+ data->on_unhandled_rejection = rb_gc_location(data->on_unhandled_rejection);
133
+ data->module_resolution_cache = rb_gc_location(data->module_resolution_cache);
134
+ data->module_source_cache = rb_gc_location(data->module_source_cache);
107
135
  }
108
136
 
109
137
  static const rb_data_type_t vm_type = {
@@ -137,8 +165,12 @@ static VALUE vm_alloc(VALUE r_self)
137
165
  data->log_listener = Qnil;
138
166
  data->alive_objects = rb_hash_new();
139
167
  data->module_loader = Qnil;
168
+ data->on_unhandled_rejection = Qnil;
169
+ data->module_resolution_cache = rb_hash_new();
170
+ data->module_source_cache = rb_hash_new();
140
171
  data->j_file_proxy_creator = JS_UNDEFINED;
141
172
  data->oom_poisoned = false;
173
+ data->disposed = false;
142
174
 
143
175
  EvalTime *eval_time = malloc(sizeof(EvalTime));
144
176
  data->eval_time = eval_time;