rusty_racer 0.2.2 → 0.2.3
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.
- checksums.yaml +4 -4
- data/README.md +31 -5
- data/ext/rusty_racer/Cargo.toml +1 -1
- data/ext/rusty_racer/src/lib.rs +21 -175
- data/lib/rusty_racer/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9a799692e0bcc6c18bbba590786cd92b0f3cd5c05c65be4da085ec3a739ae2ee
|
|
4
|
+
data.tar.gz: 0ca41e25987f9f721437abbfc1278c43d7aa688c996a1824cb342d4b1672ed70
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c63a41df38fbacdfc440a4bb61ff8f780315d2ce267a55d698505a7601557ba76a3762896dd12a4989aaf34d27ba2a7eb9c751a7249e7a71ae572a37d5af6133
|
|
7
|
+
data.tar.gz: e8deb0c3a86b25577996ee84d15f2163f6a2a8eab952d3c8592e4513f6e2cb483f3734ec7947dff22bad19cea9c5239284edd910473058baea5761921c510b8f
|
data/README.md
CHANGED
|
@@ -337,11 +337,37 @@ What happens next depends on what the stranded operation's Fiber does:
|
|
|
337
337
|
The isolate cannot be disposed after that; it is leaked, with a warning saying
|
|
338
338
|
why. If you still hold the Fiber, **`Fiber#kill` recovers it**: it resumes the
|
|
339
339
|
Fiber to unwind it, so the stranded operation finishes in order and the isolate
|
|
340
|
-
goes back to normal.
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
340
|
+
goes back to normal. The operation itself fails on the way out — see below for
|
|
341
|
+
why a kill reaches it as an ordinary error.
|
|
342
|
+
|
|
343
|
+
### Killing a thread or Fiber inside a host function
|
|
344
|
+
|
|
345
|
+
**A `Thread#kill` or `Fiber#kill` that lands while a host function's Ruby is
|
|
346
|
+
running does not kill it.** It surfaces as `RustyRacer::RuntimeError: Error:
|
|
347
|
+
Fatal` from the `eval`/`call` that was in flight, and the thread keeps going —
|
|
348
|
+
and CRuby has already marked that thread as killed, so **a second `Thread#kill`
|
|
349
|
+
is a no-op**. `Thread#raise` still works, and is the way out if you have to
|
|
350
|
+
reach in from outside.
|
|
351
|
+
|
|
352
|
+
A kill inside a **module resolver** is quieter still: the specifier it was
|
|
353
|
+
resolving simply fails to link, so the error names the import
|
|
354
|
+
(`failed to resolve module specifier "./dep.js" imported from /app.js`) with no
|
|
355
|
+
mention of a kill at all.
|
|
356
|
+
|
|
357
|
+
This is not a choice, it is the boundary. Ruby unwinds a kill with `TAG_FATAL`,
|
|
358
|
+
which arrives while V8's C++ frames are on the stack — and a `longjmp` through
|
|
359
|
+
those is not survivable, so the callback has to catch it like any other error.
|
|
360
|
+
Nor can it be put back afterwards: `rb_jump_tag` does not carry the unwind with
|
|
361
|
+
it, it re-enters whatever the VM still holds in `$!`, and anything protected
|
|
362
|
+
that ran in between (one more host function raising is enough) has cleared it.
|
|
363
|
+
Jumping into that is a segfault in the interpreter rather than a late kill. 0.2.2
|
|
364
|
+
shipped an attempt at this and had to be withdrawn in 0.2.3.
|
|
365
|
+
|
|
366
|
+
So: if you need to stop work that calls into an isolate, **stop it at a Ruby
|
|
367
|
+
boundary you control** — a flag the host function checks, a `Queue` it reads —
|
|
368
|
+
rather than by killing the thread from outside. `Isolate#terminate` stops the
|
|
369
|
+
*JavaScript* (at V8's next interrupt check, see above), which is the other half
|
|
370
|
+
of the same job.
|
|
345
371
|
|
|
346
372
|
## Installation
|
|
347
373
|
|
data/ext/rusty_racer/Cargo.toml
CHANGED
data/ext/rusty_racer/src/lib.rs
CHANGED
|
@@ -472,19 +472,6 @@ fn current_ruby_thread() -> usize {
|
|
|
472
472
|
unsafe { rb_sys::rb_thread_current() as usize }
|
|
473
473
|
}
|
|
474
474
|
|
|
475
|
-
// Identity of the calling FIBER, as its object_id — monotonic and never reused,
|
|
476
|
-
// unlike the VALUE, which is a heap address a collected Fiber hands back (and a
|
|
477
|
-
// Fiber stranded with a pending kill DOES get collected). Ids are a Fixnum on
|
|
478
|
-
// every platform this gem ships for, so the usize compared is an immediate, not
|
|
479
|
-
// a pointer that could alias in its turn. Assigning one can allocate, and this
|
|
480
|
-
// runs with V8 frames live and outside any rb_protect of ours, so it takes its
|
|
481
|
-
// own: 0 on failure, which reads as "no Fiber" at both ends and so drops a kill
|
|
482
|
-
// rather than misdelivers one. MUST be called with the GVL held.
|
|
483
|
-
fn current_fiber_id() -> usize {
|
|
484
|
-
magnus::rb_sys::protect(|| unsafe { rb_sys::rb_obj_id(rb_sys::rb_fiber_current()) })
|
|
485
|
-
.map_or(0, |id| id as usize)
|
|
486
|
-
}
|
|
487
|
-
|
|
488
475
|
// Reduce a magnus Error to a single Exception INSTANCE so it can be GC-rooted and
|
|
489
476
|
// re-raised later WITH ITS ORIGINAL CLASS. A Ruby proc's raise is already an
|
|
490
477
|
// instance; an Error::new(class, msg) from our own code becomes an instance of
|
|
@@ -560,7 +547,7 @@ fn host_fn_callback(
|
|
|
560
547
|
ruby.qnil().as_raw()
|
|
561
548
|
}) {
|
|
562
549
|
Ok(_) => out.unwrap_or_else(|| Err("host function did not complete".into())),
|
|
563
|
-
Err(e) => Err(
|
|
550
|
+
Err(e) => Err(format!("{e}")),
|
|
564
551
|
}
|
|
565
552
|
});
|
|
566
553
|
match result {
|
|
@@ -1117,10 +1104,8 @@ fn resolve_imported<'s>(
|
|
|
1117
1104
|
// calls into Ruby (so it can allocate, so it can GC) and BoxValue::new
|
|
1118
1105
|
// registers a GC root — neither is safe with the GVL released.
|
|
1119
1106
|
match with_gvl(core, RubyCall::Resolver(&spec), || {
|
|
1120
|
-
resolve_module_via_ruby(core, resolve, &spec, &ref_url, None)
|
|
1121
|
-
|
|
1122
|
-
error_to_exception(&e).map(BoxValue::new)
|
|
1123
|
-
})
|
|
1107
|
+
resolve_module_via_ruby(core, resolve, &spec, &ref_url, None)
|
|
1108
|
+
.map_err(|e| error_to_exception(&e).map(BoxValue::new))
|
|
1124
1109
|
}) {
|
|
1125
1110
|
Ok(id) => id,
|
|
1126
1111
|
// Stash the resolver's own raised exception (GC-rooted) so the
|
|
@@ -1144,7 +1129,7 @@ fn resolve_imported<'s>(
|
|
|
1144
1129
|
resolve_module_via_ruby(core, p, &spec, &ref_url, Some(here.unwrap_or(0)))
|
|
1145
1130
|
// Rendering the message reads the Ruby exception, so it too
|
|
1146
1131
|
// stays inside with_gvl.
|
|
1147
|
-
.map_err(|e|
|
|
1132
|
+
.map_err(|e| e.to_string())
|
|
1148
1133
|
}) {
|
|
1149
1134
|
Ok(id) => id,
|
|
1150
1135
|
// Unlike the static branch there is no Ruby frame waiting to
|
|
@@ -1258,17 +1243,11 @@ fn dynamic_import_cb<'s>(
|
|
|
1258
1243
|
.map(|r| r.get());
|
|
1259
1244
|
let id = match resolver_proc {
|
|
1260
1245
|
// A raising resolver only fails the import() (it rejects generically);
|
|
1261
|
-
// it must NOT abort the surrounding eval, so swallow the Err here
|
|
1262
|
-
// note_fatal first, since this is the one with_gvl site that throws its
|
|
1263
|
-
// Err away and a Thread#kill would go with it.
|
|
1246
|
+
// it must NOT abort the surrounding eval, so swallow the Err here.
|
|
1264
1247
|
Some(p) => with_gvl(core, RubyCall::Resolver(&spec), || {
|
|
1265
|
-
resolve_module_via_ruby(core, p, &spec, &referrer, Some(initiating))
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
None
|
|
1269
|
-
},
|
|
1270
|
-
)
|
|
1271
|
-
}),
|
|
1248
|
+
resolve_module_via_ruby(core, p, &spec, &referrer, Some(initiating))
|
|
1249
|
+
})
|
|
1250
|
+
.unwrap_or(None),
|
|
1272
1251
|
None => None,
|
|
1273
1252
|
};
|
|
1274
1253
|
match id {
|
|
@@ -1515,17 +1494,6 @@ struct Core {
|
|
|
1515
1494
|
// op. Owner-thread only, like the isolate itself; AtomicUsize for shared
|
|
1516
1495
|
// &Core access.
|
|
1517
1496
|
installed_stack_limit: std::sync::atomic::AtomicUsize,
|
|
1518
|
-
// Set when a callback's Ruby code unwound with TAG_FATAL — a Thread#kill —
|
|
1519
|
-
// which magnus catches like any other error because a longjmp through V8's
|
|
1520
|
-
// C++ frames is not survivable. Holds the object_id of the
|
|
1521
|
-
// Fiber that must finish the kill (never a raw VALUE: a stranded Fiber
|
|
1522
|
-
// holding a pending kill does get collected, and its address can then be
|
|
1523
|
-
// handed to a new one, whereas an object_id is monotonic and never reused);
|
|
1524
|
-
// 0 = nothing pending.
|
|
1525
|
-
// See Core::note_fatal / Core::resume_pending_fatal. Atomic for the same
|
|
1526
|
-
// reason as the rest: &Core is shared, though only the owner thread ever
|
|
1527
|
-
// touches this.
|
|
1528
|
-
pending_fatal: std::sync::atomic::AtomicUsize,
|
|
1529
1497
|
// Re-entry depth for THIS isolate, readable without a scope (the runner needs
|
|
1530
1498
|
// it to choose the scope kind before any scope exists): 0 = top-level op
|
|
1531
1499
|
// (open a fresh HandleScope from iso_ptr); >0 = a host callback is on the V8
|
|
@@ -2319,7 +2287,6 @@ impl Isolate {
|
|
|
2319
2287
|
iso_ptr,
|
|
2320
2288
|
scan_start_field: std::sync::atomic::AtomicUsize::new(0),
|
|
2321
2289
|
installed_stack_limit: std::sync::atomic::AtomicUsize::new(0),
|
|
2322
|
-
pending_fatal: std::sync::atomic::AtomicUsize::new(0),
|
|
2323
2290
|
depth: std::sync::atomic::AtomicU32::new(0),
|
|
2324
2291
|
procs: Mutex::new(ProcTable::default()),
|
|
2325
2292
|
default_timeout_ms: timeout_ms,
|
|
@@ -2580,58 +2547,10 @@ impl Core {
|
|
|
2580
2547
|
}
|
|
2581
2548
|
}
|
|
2582
2549
|
|
|
2583
|
-
// Finish a Thread#kill that a callback had to swallow (see note_fatal). This
|
|
2584
|
-
// is a longjmp — the same rb_jump_tag magnus performs for an Error::Jump
|
|
2585
|
-
// handed back to it — so nothing between here and Ruby runs Drop, and it may
|
|
2586
|
-
// only be called where no frame in between still owns anything that matters.
|
|
2587
|
-
// That rules out the end of `run`: instantiate_module parks the op's resolver
|
|
2588
|
-
// across the call and restores it afterwards, and skipping THAT would leave a
|
|
2589
|
-
// dead op's resolver parked for a later dynamic import to call. The end of
|
|
2590
|
-
// reply_value is past every such restore, and reaching it is what every
|
|
2591
|
-
// operation that can run Ruby at all does.
|
|
2592
|
-
//
|
|
2593
|
-
// An operation that returns Err from `run` — only a panic, which poisons the
|
|
2594
|
-
// isolate — doesn't reach it, and the kill is then dropped by whichever
|
|
2595
|
-
// operation gets here next (see the Fiber check). Frames above still leak
|
|
2596
|
-
// whatever they hold (an argument String, say), which is why every caller with
|
|
2597
|
-
// cleanup of its own runs that cleanup BEFORE calling this.
|
|
2598
|
-
fn resume_pending_fatal<T>(&self, outcome: Result<T, Error>) -> Result<T, Error> {
|
|
2599
|
-
let pending = self.pending_fatal.swap(0, Ordering::SeqCst);
|
|
2600
|
-
// Nothing pending — the case every op takes, and one atomic load.
|
|
2601
|
-
if pending == 0 {
|
|
2602
|
-
return outcome;
|
|
2603
|
-
}
|
|
2604
|
-
// A kill belongs to the Fiber whose callback swallowed it, and finishing
|
|
2605
|
-
// it anywhere else would kill an unrelated caller — the main thread, say,
|
|
2606
|
-
// mid-eval, with no exception and no message. A mismatch is an ordinary
|
|
2607
|
-
// outcome, not a should-not-happen: when the script CATCHES the error the
|
|
2608
|
-
// killed callback threw, that operation may never end, and the next one to
|
|
2609
|
-
// get here is somebody else's. Drop the kill rather than deliver it to the
|
|
2610
|
-
// wrong Fiber. (CRuby's own Fiber#kill bookkeeping still terminates such a
|
|
2611
|
-
// Fiber on its next resume; only its return value is lost.)
|
|
2612
|
-
if pending != current_fiber_id() {
|
|
2613
|
-
return outcome;
|
|
2614
|
-
}
|
|
2615
|
-
drop(outcome);
|
|
2616
|
-
// enum ruby_tag_type's RUBY_TAG_FATAL; not in rb_sys's bindings
|
|
2617
|
-
// (bindgen skips the anonymous enum), and stable since 1.9.
|
|
2618
|
-
const RUBY_TAG_FATAL: std::os::raw::c_int = 8;
|
|
2619
|
-
unsafe { rb_sys::rb_jump_tag(RUBY_TAG_FATAL) };
|
|
2620
|
-
}
|
|
2621
|
-
|
|
2622
2550
|
// Map a terminal reply to a Ruby value (the common eval/call/run shape).
|
|
2623
2551
|
// &self so a Terminated outcome can pick up the JS stack the watchdog snapshot
|
|
2624
2552
|
// captured (see timeout_interrupt / take_timeout_backtrace).
|
|
2625
2553
|
fn reply_value(&self, ruby: &Ruby, reply: VmReply) -> Result<Value, Error> {
|
|
2626
|
-
let outcome = self.reply_value_deferred(ruby, reply);
|
|
2627
|
-
// Every operation that can run Ruby — and so can have a Thread#kill
|
|
2628
|
-
// swallowed by one of its callbacks — ends here, except the few whose own
|
|
2629
|
-
// cleanup has to run first; those call the two halves in order.
|
|
2630
|
-
self.resume_pending_fatal(outcome)
|
|
2631
|
-
}
|
|
2632
|
-
|
|
2633
|
-
// reply_value without finishing a swallowed kill.
|
|
2634
|
-
fn reply_value_deferred(&self, ruby: &Ruby, reply: VmReply) -> Result<Value, Error> {
|
|
2635
2554
|
match reply {
|
|
2636
2555
|
VmReply::Done(Ok(val)) => jsval_to_ruby(ruby, &val),
|
|
2637
2556
|
// Clone (don't take): a nested timeout's terminate unwinds the whole op
|
|
@@ -2659,64 +2578,6 @@ impl Core {
|
|
|
2659
2578
|
.clone()
|
|
2660
2579
|
}
|
|
2661
2580
|
|
|
2662
|
-
// A Ruby error raised under a live op cannot be allowed to longjmp — it would
|
|
2663
|
-
// cross V8's C++ frames — so every callback catches it and throws it into JS
|
|
2664
|
-
// as a message instead. That is right for an exception and wrong for exactly
|
|
2665
|
-
// one thing: Thread#kill unwinds with TAG_FATAL, which magnus catches like
|
|
2666
|
-
// anything else, and a killed thread that is merely told about it in
|
|
2667
|
-
// JavaScript is not killed at all — it goes on to run whatever comes next,
|
|
2668
|
-
// while the op's caller is handed a fabricated `RustyRacer::RuntimeError:
|
|
2669
|
-
// Error: Fatal`. Remember it here; Core::run re-asserts it the moment the op
|
|
2670
|
-
// is over and there are no V8 frames left to cross, which is what magnus
|
|
2671
|
-
// would have done with the jump if it could have.
|
|
2672
|
-
//
|
|
2673
|
-
// Only Fatal. The other jumps (a `break` or `next` out of a host proc) have
|
|
2674
|
-
// no live block to return to by the time we could resume them, so they stay
|
|
2675
|
-
// what they are today: an error on the JavaScript side.
|
|
2676
|
-
//
|
|
2677
|
-
// The kill lands at the END of the operation, not at the callback: the
|
|
2678
|
-
// callback still has to return through V8, and what it returns is an ordinary
|
|
2679
|
-
// JavaScript exception, which the script may catch and carry on from — during
|
|
2680
|
-
// which it can call further host functions, running Ruby on the already-killed
|
|
2681
|
-
// thread.
|
|
2682
|
-
//
|
|
2683
|
-
// Terminating the isolate here to make that uncatchable was tried and
|
|
2684
|
-
// REJECTED, for a reason worth writing down because the obvious objection is
|
|
2685
|
-
// the wrong one. V8 does see it: a termination requested from inside a host
|
|
2686
|
-
// callback survives the callback and is observed at the next interrupt check,
|
|
2687
|
-
// which is any JavaScript function entry or a loop long enough to exhaust
|
|
2688
|
-
// Ignition's interrupt budget — only a degenerate tail of host calls and
|
|
2689
|
-
// literals escapes. The problem is what happens when it escapes: the request
|
|
2690
|
-
// stays ARMED, and the sweep that clears a stale one runs only at an outermost
|
|
2691
|
-
// request (see service_request), which is exactly what a stranded operation
|
|
2692
|
-
// leaves the isolate without. It would then terminate an unrelated later
|
|
2693
|
-
// operation, which is a worse failure than the one being fixed — and it does
|
|
2694
|
-
// not even close the window it was for, since a script looping on host calls
|
|
2695
|
-
// alone reaches no interrupt check either.
|
|
2696
|
-
fn note_fatal(&self, e: &Error) {
|
|
2697
|
-
if !matches!(
|
|
2698
|
-
e.error_type(),
|
|
2699
|
-
magnus::error::ErrorType::Jump(magnus::error::Tag::Fatal)
|
|
2700
|
-
) {
|
|
2701
|
-
return;
|
|
2702
|
-
}
|
|
2703
|
-
// Which Fiber has to finish the kill: this one, the one the killed
|
|
2704
|
-
// callback was running on. Checked again at the other end, so a pending
|
|
2705
|
-
// kill can never land on an unrelated caller.
|
|
2706
|
-
self.pending_fatal
|
|
2707
|
-
.store(current_fiber_id(), Ordering::SeqCst);
|
|
2708
|
-
}
|
|
2709
|
-
|
|
2710
|
-
// note_fatal + the message the callback will throw, for the map_err sites.
|
|
2711
|
-
// Rendering is safe to do here, outside any rb_protect with V8 frames live:
|
|
2712
|
-
// magnus formats an exception from its class name and address rather than
|
|
2713
|
-
// calling #message or #inspect, so a caller whose own class raises from those
|
|
2714
|
-
// (checked) cannot longjmp out of this.
|
|
2715
|
-
fn swallow(&self, e: Error) -> String {
|
|
2716
|
-
self.note_fatal(&e);
|
|
2717
|
-
e.to_string()
|
|
2718
|
-
}
|
|
2719
|
-
|
|
2720
2581
|
fn call_proc(&self, ruby: &Ruby, host_fn_id: usize, args: &[JsVal]) -> Result<JsVal, String> {
|
|
2721
2582
|
let proc = {
|
|
2722
2583
|
let procs = self.procs.lock().unwrap();
|
|
@@ -2738,16 +2599,16 @@ impl Core {
|
|
|
2738
2599
|
let ruby_args = ruby.ary_new_capa(args.len());
|
|
2739
2600
|
for v in args {
|
|
2740
2601
|
ruby_args
|
|
2741
|
-
.push(jsval_to_ruby(ruby, v).map_err(|e|
|
|
2742
|
-
.map_err(|e|
|
|
2602
|
+
.push(jsval_to_ruby(ruby, v).map_err(|e| e.to_string())?)
|
|
2603
|
+
.map_err(|e| e.to_string())?;
|
|
2743
2604
|
}
|
|
2744
2605
|
// SAFETY: ruby_args is a live local (so GC keeps it and its elements) and
|
|
2745
2606
|
// is not mutated while the slice is borrowed — as_slice's contract. A VM
|
|
2746
2607
|
// op the proc issues re-enters Core::run (depth > 0) directly — no nested
|
|
2747
2608
|
// frame bookkeeping is needed any more (the call stack IS the nesting).
|
|
2748
2609
|
let result: Result<Value, Error> = proc.call(unsafe { ruby_args.as_slice() });
|
|
2749
|
-
let value = result.map_err(|e|
|
|
2750
|
-
ruby_to_jsval(value).map_err(|e|
|
|
2610
|
+
let value = result.map_err(|e| e.to_string())?;
|
|
2611
|
+
ruby_to_jsval(value).map_err(|e| e.to_string())
|
|
2751
2612
|
}
|
|
2752
2613
|
|
|
2753
2614
|
// Context#call (and call_void). Resolves a dotted function path
|
|
@@ -2931,20 +2792,11 @@ impl Core {
|
|
|
2931
2792
|
|
|
2932
2793
|
fn reset(&self, ruby: &Ruby, context_id: i32) -> Result<Value, Error> {
|
|
2933
2794
|
let reply = self.run(ruby, Request::Reset { context_id })?;
|
|
2934
|
-
|
|
2935
|
-
// before a swallowed kill is finished, or the jump skips it and this
|
|
2936
|
-
// realm's procs stay GC-rooted and their slots unrecycled for the life of
|
|
2937
|
-
// the isolate — a permanent leak in a process that goes on running, since
|
|
2938
|
-
// a killed FIBER leaves its thread alive.
|
|
2939
|
-
let out = self.reply_value_deferred(ruby, reply);
|
|
2795
|
+
let out = self.reply_value(ruby, reply)?;
|
|
2940
2796
|
// Only on success — a refused reset (unknown/suspended realm) keeps
|
|
2941
|
-
// its attached fns callable.
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
if out.is_ok() {
|
|
2945
|
-
self.release_context_procs(context_id);
|
|
2946
|
-
}
|
|
2947
|
-
self.resume_pending_fatal(out)
|
|
2797
|
+
// its attached fns callable.
|
|
2798
|
+
self.release_context_procs(context_id);
|
|
2799
|
+
Ok(out)
|
|
2948
2800
|
}
|
|
2949
2801
|
|
|
2950
2802
|
// Build a new context; returns its id (replied as an Int).
|
|
@@ -2956,12 +2808,9 @@ impl Core {
|
|
|
2956
2808
|
|
|
2957
2809
|
fn dispose_context(&self, ruby: &Ruby, context_id: i32) -> Result<(), Error> {
|
|
2958
2810
|
let reply = self.run(ruby, Request::DisposeContext { context_id })?;
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
self.release_context_procs(context_id);
|
|
2963
|
-
}
|
|
2964
|
-
self.resume_pending_fatal(out.map(|_| ()))
|
|
2811
|
+
self.reply_value(ruby, reply)?;
|
|
2812
|
+
self.release_context_procs(context_id);
|
|
2813
|
+
Ok(())
|
|
2965
2814
|
}
|
|
2966
2815
|
|
|
2967
2816
|
// Thin ESM primitives. compile_module returns the new module's id.
|
|
@@ -3038,10 +2887,7 @@ impl Core {
|
|
|
3038
2887
|
// Reclaim THIS op's resolver error and restore the outer op's pair.
|
|
3039
2888
|
let (_, resolver_err) = self.swap_instantiate(saved_resolve, saved_err);
|
|
3040
2889
|
if let Some(exc) = resolver_err {
|
|
3041
|
-
|
|
3042
|
-
// just as much the end of the op, and skipping it would leave a
|
|
3043
|
-
// swallowed kill for some later op to assert.
|
|
3044
|
-
return self.resume_pending_fatal(Err(Error::from(*exc)));
|
|
2890
|
+
return Err(Error::from(*exc));
|
|
3045
2891
|
}
|
|
3046
2892
|
self.reply_value(ruby, reply?)
|
|
3047
2893
|
}
|
|
@@ -3266,7 +3112,7 @@ impl Drop for Core {
|
|
|
3266
3112
|
so it cannot be disposed and is leaked.\n\
|
|
3267
3113
|
The usual cause is a host function that yielded out of a Fiber \
|
|
3268
3114
|
which was never resumed;\n\
|
|
3269
|
-
`Fiber#kill`
|
|
3115
|
+
`Fiber#kill` recovers one if you still hold it. See\n\
|
|
3270
3116
|
https://github.com/ursm/rusty_racer#fibers\n"
|
|
3271
3117
|
);
|
|
3272
3118
|
LEAKED_ISOLATES.fetch_add(1, Ordering::Relaxed);
|
data/lib/rusty_racer/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rusty_racer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Keita Urashima
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
date: 2026-08-26 00:00:00.000000000 Z
|
|
@@ -54,7 +54,7 @@ metadata:
|
|
|
54
54
|
source_code_uri: https://github.com/ursm/rusty_racer
|
|
55
55
|
bug_tracker_uri: https://github.com/ursm/rusty_racer/issues
|
|
56
56
|
rubygems_mfa_required: 'true'
|
|
57
|
-
post_install_message:
|
|
57
|
+
post_install_message:
|
|
58
58
|
rdoc_options: []
|
|
59
59
|
require_paths:
|
|
60
60
|
- lib
|
|
@@ -70,7 +70,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
70
70
|
version: '0'
|
|
71
71
|
requirements: []
|
|
72
72
|
rubygems_version: 3.5.22
|
|
73
|
-
signing_key:
|
|
73
|
+
signing_key:
|
|
74
74
|
specification_version: 4
|
|
75
75
|
summary: Embed V8 in Ruby via rusty_v8 + Magnus (rb-sys)
|
|
76
76
|
test_files: []
|