Skip to content

Commit 001cccc

Browse files
andrykonchineregon
authored andcommitted
[GR-18163] Separate rb_set_errinfo/rb_errinfo and $!
PullRequest: truffleruby/4312
2 parents 22d0829 + 24bfa4c commit 001cccc

File tree

19 files changed

+253
-139
lines changed

19 files changed

+253
-139
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ Compatibility:
4040
* Fix formatting in `Exception#full_message` when `RuntimeError` is not handled and `highlight` option is specified (@andrykonchin).
4141
* Fix `String#encode` and convert fallback values into String using `#to_str` (@andrykonchin).
4242
* Fix `Kernel.warn` and don't call `Warning#warn` if a specified category is disabled (@andrykonchin).
43+
* Fix `$!` global variable and make it fiber-local (@andrykonchin).
44+
* Fix `rb_set_errinfo` and `rb_errinfo` and store an error separately from `$!` (#2890, @andrykonchin).
4345

4446
Performance:
4547

lib/truffle/truffle/cext.rb

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ def rb_reg_compile(pattern, options)
721721
nil
722722
end
723723
if err
724-
Primitive.thread_set_exception(err)
724+
Primitive.fiber_set_error_info(err)
725725
nil
726726
else
727727
result
@@ -1239,7 +1239,7 @@ def rb_protect(function, arg, write_status, status)
12391239
unless Primitive.nil?(e)
12401240
store_exception(e)
12411241
pos = extract_tag(e)
1242-
Primitive.thread_set_exception(extract_ruby_exception(e))
1242+
Primitive.fiber_set_error_info(extract_ruby_exception(e))
12431243
end
12441244

12451245
Truffle::Interop.execute_without_conversion(write_status, status, pos)
@@ -1252,7 +1252,7 @@ def rb_jump_tag(pos)
12521252
e = retrieve_exception
12531253
tag = extract_tag(e)
12541254
raise RuntimeError, 'mismatch between jump tag and captured exception' unless pos == tag
1255-
Primitive.thread_set_exception(nil)
1255+
Primitive.fiber_set_error_info(nil)
12561256
raise_exception(e)
12571257
end
12581258
end
@@ -1307,7 +1307,7 @@ def rb_exc_raise(exception)
13071307

13081308
def rb_set_errinfo(error)
13091309
if Primitive.nil?(error) || Primitive.is_a?(error, Exception)
1310-
Primitive.thread_set_exception(error)
1310+
Primitive.fiber_set_error_info(error)
13111311
else
13121312
raise TypeError, 'assigning non-exception to ?!'
13131313
end
@@ -1318,7 +1318,7 @@ def rb_make_exception(args)
13181318
end
13191319

13201320
def rb_errinfo
1321-
$!
1321+
Primitive.fiber_get_error_info
13221322
end
13231323

13241324
def rb_arity_error_string(arg_count, min, max)
@@ -1494,7 +1494,7 @@ def rb_get_alloc_func(ruby_class)
14941494
begin
14951495
allocate_method = ruby_class.method(:__allocate__).owner
14961496
rescue NameError
1497-
nil
1497+
nil # it's fine to call this on a class that doesn't have an allocator
14981498
else
14991499
Primitive.object_hidden_var_get(allocate_method, ALLOCATOR_FUNC)
15001500
end
@@ -1837,19 +1837,31 @@ def rb_ensure(b_proc, data1, e_proc, data2)
18371837
begin
18381838
Primitive.interop_execute(POINTER_TO_POINTER_WRAPPER, [b_proc, data1])
18391839
ensure
1840-
Primitive.interop_execute(POINTER_TO_POINTER_WRAPPER, [e_proc, data2])
1840+
errinfo = Primitive.fiber_get_error_info
1841+
Primitive.fiber_set_error_info($!)
1842+
begin
1843+
Primitive.interop_execute(POINTER_TO_POINTER_WRAPPER, [e_proc, data2])
1844+
ensure
1845+
Primitive.fiber_set_error_info(errinfo)
1846+
end
18411847
end
18421848
end
18431849
Truffle::Graal.always_split instance_method(:rb_ensure)
18441850

18451851
def rb_rescue(b_proc, data1, r_proc, data2)
18461852
begin
18471853
Primitive.interop_execute(POINTER_TO_POINTER_WRAPPER, [b_proc, data1])
1848-
rescue StandardError => e
1854+
rescue StandardError => exc
18491855
if Truffle::Interop.null?(r_proc)
18501856
Primitive.cext_wrap(nil)
18511857
else
1852-
Primitive.interop_execute(POINTER2_TO_POINTER_WRAPPER, [r_proc, data2, Primitive.cext_wrap(e)])
1858+
errinfo = Primitive.fiber_get_error_info
1859+
Primitive.fiber_set_error_info(exc)
1860+
begin
1861+
Primitive.interop_execute(POINTER2_TO_POINTER_WRAPPER, [r_proc, data2, Primitive.cext_wrap(exc)])
1862+
ensure
1863+
Primitive.fiber_set_error_info(errinfo)
1864+
end
18531865
end
18541866
end
18551867
end
@@ -1858,8 +1870,14 @@ def rb_rescue(b_proc, data1, r_proc, data2)
18581870
def rb_rescue2(b_proc, data1, r_proc, data2, rescued)
18591871
begin
18601872
Primitive.interop_execute(POINTER_TO_POINTER_WRAPPER, [b_proc, data1])
1861-
rescue *rescued => e
1862-
Primitive.interop_execute(POINTER2_TO_POINTER_WRAPPER, [r_proc, data2, Primitive.cext_wrap(e)])
1873+
rescue *rescued => exc
1874+
errinfo = Primitive.fiber_get_error_info
1875+
Primitive.fiber_set_error_info(exc)
1876+
begin
1877+
Primitive.interop_execute(POINTER2_TO_POINTER_WRAPPER, [r_proc, data2, Primitive.cext_wrap(exc)])
1878+
ensure
1879+
Primitive.fiber_set_error_info(errinfo)
1880+
end
18631881
end
18641882
end
18651883
Truffle::Graal.always_split instance_method(:rb_rescue2)

lib/truffle/truffle/cext_ruby.rb

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,9 @@ def rb_define_method(mod, name, function, argc)
3333
args = [function, Primitive.cext_wrap(self), *args.map! { |arg| Primitive.cext_wrap(arg) }]
3434
end
3535

36-
exc = $!
37-
Primitive.thread_set_exception(nil)
3836
# We must set block argument if given here so that the
3937
# `rb_block_*` functions will be able to find it by walking the stack.
40-
res = Primitive.call_with_c_mutex_and_frame_and_unwrap(wrapper, args, Primitive.caller_special_variables_if_available, block)
41-
Primitive.thread_set_exception(exc)
42-
res
38+
Primitive.call_with_c_mutex_and_frame_and_unwrap(wrapper, args, Primitive.caller_special_variables_if_available, block)
4339
end
4440

4541
# Even if the argc is -2, the arity number

spec/ruby/core/kernel/raise_spec.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,22 @@
4646
cause = StandardError.new
4747
-> { raise(cause: cause) }.should raise_error(ArgumentError)
4848
end
49+
50+
it "re-raises a rescued exception" do
51+
-> do
52+
begin
53+
raise StandardError, "aaa"
54+
rescue Exception
55+
begin
56+
raise ArgumentError
57+
rescue ArgumentError
58+
end
59+
60+
# should raise StandardError "aaa"
61+
raise
62+
end
63+
end.should raise_error(StandardError, "aaa")
64+
end
4965
end
5066

5167
describe "Kernel#raise" do

spec/ruby/language/predefined_spec.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,16 @@ def test(arg)
243243
end
244244

245245
describe "Predefined global $!" do
246+
it "is Fiber-local" do
247+
Fiber.new do
248+
raise "hi"
249+
rescue
250+
Fiber.yield
251+
end.resume
252+
253+
$!.should == nil
254+
end
255+
246256
# See http://jira.codehaus.org/browse/JRUBY-5550
247257
it "remains nil after a failed core class \"checked\" coercion against a class that defines method_missing" do
248258
$!.should == nil

spec/ruby/optional/capi/ext/kernel_spec.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,12 @@
77
extern "C" {
88
#endif
99

10-
VALUE kernel_spec_call_proc(VALUE arg_array) {
10+
static VALUE kernel_spec_call_proc(VALUE arg_array) {
1111
VALUE arg = rb_ary_pop(arg_array);
1212
VALUE proc = rb_ary_pop(arg_array);
1313
return rb_funcall(proc, rb_intern("call"), 1, arg);
1414
}
1515

16-
VALUE kernel_spec_call_proc_raise(VALUE arg_array, VALUE raised_exc) {
17-
return kernel_spec_call_proc(arg_array);
18-
}
19-
2016
static VALUE kernel_spec_rb_block_given_p(VALUE self) {
2117
return rb_block_given_p() ? Qtrue : Qfalse;
2218
}
@@ -134,7 +130,16 @@ VALUE kernel_spec_rb_throw_obj(VALUE self, VALUE obj, VALUE result) {
134130
return ID2SYM(rb_intern("rb_throw_failed"));
135131
}
136132

137-
VALUE kernel_spec_call_proc_with_raised_exc(VALUE arg_array, VALUE raised_exc) {
133+
VALUE kernel_spec_rb_errinfo(VALUE self) {
134+
return rb_errinfo();
135+
}
136+
137+
VALUE kernel_spec_rb_set_errinfo(VALUE self, VALUE exc) {
138+
rb_set_errinfo(exc);
139+
return Qnil;
140+
}
141+
142+
static VALUE kernel_spec_call_proc_with_raised_exc(VALUE arg_array, VALUE raised_exc) {
138143
VALUE argv[2];
139144
int argc;
140145

@@ -181,7 +186,7 @@ VALUE kernel_spec_rb_rescue2(int argc, VALUE *args, VALUE self) {
181186
rb_ary_push(raise_array, args[3]);
182187

183188
return rb_rescue2(kernel_spec_call_proc, main_array,
184-
kernel_spec_call_proc_raise, raise_array, args[4], args[5], (VALUE)0);
189+
kernel_spec_call_proc_with_raised_exc, raise_array, args[4], args[5], (VALUE)0);
185190
}
186191

187192
static VALUE kernel_spec_rb_protect_yield(VALUE self, VALUE obj, VALUE ary) {
@@ -195,7 +200,7 @@ static VALUE kernel_spec_rb_protect_yield(VALUE self, VALUE obj, VALUE ary) {
195200
return res;
196201
}
197202

198-
static VALUE kernel_spec_rb_protect_errinfo(VALUE self, VALUE obj, VALUE ary) {
203+
static VALUE kernel_spec_rb_protect_ignore_status(VALUE self, VALUE obj, VALUE ary) {
199204
int status = 0;
200205
VALUE res = rb_protect(rb_yield, obj, &status);
201206
rb_ary_store(ary, 0, INT2NUM(23));
@@ -382,10 +387,13 @@ void Init_kernel_spec(void) {
382387
rb_define_method(cls, "rb_raise", kernel_spec_rb_raise, 1);
383388
rb_define_method(cls, "rb_throw", kernel_spec_rb_throw, 1);
384389
rb_define_method(cls, "rb_throw_obj", kernel_spec_rb_throw_obj, 2);
390+
rb_define_method(cls, "rb_errinfo", kernel_spec_rb_errinfo, 0);
391+
rb_define_method(cls, "rb_set_errinfo", kernel_spec_rb_set_errinfo, 1);
392+
rb_define_method(cls, "rb_rescue", kernel_spec_rb_rescue, 4);
385393
rb_define_method(cls, "rb_rescue", kernel_spec_rb_rescue, 4);
386394
rb_define_method(cls, "rb_rescue2", kernel_spec_rb_rescue2, -1);
387395
rb_define_method(cls, "rb_protect_yield", kernel_spec_rb_protect_yield, 2);
388-
rb_define_method(cls, "rb_protect_errinfo", kernel_spec_rb_protect_errinfo, 2);
396+
rb_define_method(cls, "rb_protect_ignore_status", kernel_spec_rb_protect_ignore_status, 2);
389397
rb_define_method(cls, "rb_protect_null_status", kernel_spec_rb_protect_null_status, 1);
390398
rb_define_method(cls, "rb_eval_string_protect", kernel_spec_rb_eval_string_protect, 2);
391399
rb_define_method(cls, "rb_catch", kernel_spec_rb_catch, 2);

0 commit comments

Comments
 (0)