Skip to content

Commit 2159262

Browse files
committed
[GR-16199] Refactor C block access for better performance.
PullRequest: truffleruby/870
2 parents 4920b80 + e0208cc commit 2159262

File tree

5 files changed

+100
-84
lines changed

5 files changed

+100
-84
lines changed

lib/truffle/truffle/cext.rb

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,11 @@ def to_native
200200
end
201201

202202
def [](index)
203-
Truffle::CExt.rb_tr_wrap(array[index])
203+
Truffle.invoke_primitive(:cext_wrap, array[index])
204204
end
205205

206206
def []=(index, value)
207-
array[index] = Truffle::CExt.rb_tr_unwrap(value)
207+
array[index] = Truffle.invoke_primitive(:cext_unwrap, value)
208208
end
209209

210210
def native?
@@ -962,7 +962,7 @@ def rb_funcallv(recv, meth, args)
962962

963963
def rb_funcall(recv, meth, n, *args)
964964
# see #call_with_thread_locally_stored_block
965-
thread_local_block = Thread.current[:__C_BLOCK__]
965+
thread_local_block = Thread.current[:__C_BLOCK__]
966966
Thread.current[:__C_BLOCK__] = nil
967967
recv.__send__(meth, *args, &thread_local_block)
968968
ensure
@@ -1032,7 +1032,7 @@ def rb_hash_set_ifnone(hash, value)
10321032

10331033
def rb_hash_foreach(hash, func, farg)
10341034
hash.each do |key, value|
1035-
st_result = Truffle::Interop.execute_without_conversion(func, rb_tr_wrap(key), rb_tr_wrap(value), farg)
1035+
st_result = Truffle::Interop.execute_without_conversion(func, Truffle.invoke_primitive(:cext_wrap, key), Truffle.invoke_primitive(:cext_wrap, value), farg)
10361036

10371037
case st_result
10381038
when ST_CONTINUE
@@ -1055,8 +1055,8 @@ def rb_path_to_class(path)
10551055

10561056
def rb_proc_new(function, value)
10571057
Proc.new do |*args|
1058-
Truffle::CExt.rb_tr_unwrap(
1059-
Truffle.invoke_primitive(:call_with_c_mutex, function, args.map! { |arg| Truffle::CExt.rb_tr_wrap(arg) }))
1058+
Truffle.invoke_primitive(:cext_unwrap,
1059+
Truffle.invoke_primitive(:call_with_c_mutex, function, args.map! { |arg| Truffle.invoke_primitive( :cext_wrap, arg) }))
10601060
end
10611061
end
10621062

@@ -1088,7 +1088,7 @@ def rb_protect_with_block(function, arg)
10881088
# function called will do that. In general we try not to touch the
10891089
# values passed in or out of protected functions as C extensions
10901090
# may accept or return arbitrary pointers rather than ruby VALUEs.
1091-
res = rb_tr_wrap(nil)
1091+
res = Truffle.invoke_primitive(:cext_wrap, nil)
10921092
pos = 0
10931093
e = capture_exception do
10941094
res = Truffle::Interop.execute_without_conversion(function, arg)
@@ -1271,7 +1271,7 @@ def rb_enumeratorize(obj, meth, args)
12711271

12721272
def rb_enumeratorize_with_size(obj, meth, args, size_fn)
12731273
return rb_enumeratorize(obj, meth, args) if size_fn.nil?
1274-
enum = obj.to_enum(meth, *args) { rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex, size_fn, [rb_tr_wrap(obj), rb_tr_wrap(args), rb_tr_wrap(enum)])) }
1274+
enum = obj.to_enum(meth, *args) { rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex, size_fn, [Truffle.invoke_primitive(:cext_wrap, obj), Truffle.invoke_primitive(:cext_wrap, args), Truffle.invoke_primitive(:cext_wrap, enum)])) }
12751275
enum
12761276
end
12771277

@@ -1281,7 +1281,7 @@ def rb_eval_string(str)
12811281

12821282
def rb_define_alloc_func(ruby_class, function)
12831283
ruby_class.singleton_class.define_method(:__allocate__) do
1284-
Truffle::CExt.rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex, function, [Truffle::CExt.rb_tr_wrap(self)]))
1284+
Truffle.invoke_primitive( :cext_unwrap, Truffle.invoke_primitive(:call_with_c_mutex, function, [Truffle.invoke_primitive( :cext_wrap, self)]))
12851285
end
12861286
class << ruby_class
12871287
private :__allocate__
@@ -1399,7 +1399,7 @@ def rb_mutex_sleep(mutex, timeout)
13991399

14001400
def rb_mutex_synchronize(mutex, func, arg)
14011401
mutex.synchronize do
1402-
rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex, func, [rb_tr_wrap(arg)]))
1402+
rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex, func, [Truffle.invoke_primitive(:cext_wrap, arg)]))
14031403
end
14041404
end
14051405

@@ -1513,7 +1513,7 @@ def send_splatted(object, method, args)
15131513

15141514
def rb_block_call(object, method, args, func, data)
15151515
object.__send__(method, *args) do |*block_args|
1516-
rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex, func, [rb_tr_wrap(block_args.first), data, block_args.size, RARRAY_PTR(block_args), nil]))
1516+
rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex, func, [Truffle.invoke_primitive(:cext_wrap, block_args.first), data, block_args.size, RARRAY_PTR(block_args), nil]))
15171517
end
15181518
end
15191519

@@ -1529,35 +1529,35 @@ def rb_rescue(b_proc, data1, r_proc, data2)
15291529
begin
15301530
Truffle.invoke_primitive(:call_with_c_mutex, b_proc, [data1])
15311531
rescue StandardError => e
1532-
Truffle.invoke_primitive(:call_with_c_mutex, r_proc, [data2, rb_tr_wrap(e)])
1532+
Truffle.invoke_primitive(:call_with_c_mutex, r_proc, [data2, Truffle.invoke_primitive(:cext_wrap, e)])
15331533
end
15341534
end
15351535

15361536
def rb_rescue2(b_proc, data1, r_proc, data2, rescued)
15371537
begin
15381538
Truffle.invoke_primitive(:call_with_c_mutex, b_proc, [data1])
15391539
rescue *rescued => e
1540-
Truffle.invoke_primitive(:call_with_c_mutex, r_proc, [data2, rb_tr_wrap(e)])
1540+
Truffle.invoke_primitive(:call_with_c_mutex, r_proc, [data2, Truffle.invoke_primitive(:cext_wrap, e)])
15411541
end
15421542
end
15431543

15441544
def rb_exec_recursive(func, obj, arg)
15451545
result = nil
15461546

15471547
recursive = Thread.detect_recursion(obj) do
1548-
result = rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex, func, [rb_tr_wrap(obj), rb_tr_wrap(arg), 0]))
1548+
result = rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex, func, [Truffle.invoke_primitive(:cext_wrap, obj), Truffle.invoke_primitive(:cext_wrap, arg), 0]))
15491549
end
15501550

15511551
if recursive
1552-
rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex, func, [rb_tr_wrap(obj), rb_tr_wrap(arg), 1]))
1552+
rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex, func, [Truffle.invoke_primitive(:cext_wrap, obj), Truffle.invoke_primitive(:cext_wrap, arg), 1]))
15531553
else
15541554
result
15551555
end
15561556
end
15571557

15581558
def rb_catch_obj(tag, func, data)
15591559
catch tag do |caught|
1560-
rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex, func, [rb_tr_wrap(caught), rb_tr_wrap(data), rb_tr_wrap(nil)]))
1560+
rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex, func, [Truffle.invoke_primitive(:cext_wrap, caught), Truffle.invoke_primitive(:cext_wrap, data), Truffle.invoke_primitive(:cext_wrap, nil)]))
15611561
end
15621562
end
15631563

@@ -1656,7 +1656,7 @@ def rb_iterate(iteration, iterated_object, callback, callback_arg)
16561656
end
16571657
else
16581658
call_with_thread_locally_stored_block iteration, iterated_object do |block_arg|
1659-
rb_tr_unwrap Truffle.invoke_primitive(:call_with_c_mutex, callback, [rb_tr_wrap(block_arg), rb_tr_wrap(callback_arg), rb_tr_wrap(nil)])
1659+
rb_tr_unwrap Truffle.invoke_primitive(:call_with_c_mutex, callback, [Truffle.invoke_primitive(:cext_wrap, block_arg), Truffle.invoke_primitive(:cext_wrap, callback_arg), Truffle.invoke_primitive(:cext_wrap, nil)])
16601660
end
16611661
end
16621662
end
@@ -1762,11 +1762,11 @@ def rb_define_hooked_variable(name, gvar, getter, setter)
17621762
id = name.to_sym
17631763

17641764
getter_proc = -> {
1765-
rb_tr_unwrap Truffle.invoke_primitive(:call_with_c_mutex, getter, [rb_tr_wrap(id), gvar, rb_tr_wrap(nil)])
1765+
rb_tr_unwrap Truffle.invoke_primitive(:call_with_c_mutex, getter, [Truffle.invoke_primitive(:cext_wrap, id), gvar, Truffle.invoke_primitive(:cext_wrap, nil)])
17661766
}
17671767

17681768
setter_proc = -> value {
1769-
Truffle.invoke_primitive(:call_with_c_mutex, setter, [rb_tr_wrap(value), rb_tr_wrap(id), gvar, rb_tr_wrap(nil)])
1769+
Truffle.invoke_primitive(:call_with_c_mutex, setter, [Truffle.invoke_primitive(:cext_wrap, value), Truffle.invoke_primitive(:cext_wrap, id), gvar, Truffle.invoke_primitive(:cext_wrap, nil)])
17701770
}
17711771

17721772
Truffle::KernelOperations.define_hooked_variable id, getter_proc, setter_proc
@@ -1837,4 +1837,12 @@ def rb_sprintf(format, *args)
18371837
sprintf(f, *args) rescue raise ArgumentError, "Bad format string #{f}."
18381838
end
18391839

1840+
def rb_tr_wrap(obj)
1841+
Truffle.invoke_primitive :cext_wrap, obj
1842+
end
1843+
1844+
def rb_tr_unwrap(wrapper)
1845+
Truffle.invoke_primitive :cext_unwrap, wrapper
1846+
end
1847+
18401848
end

lib/truffle/truffle/cext_ruby.rb

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,22 @@ def rb_define_method(mod, name, function, argc)
1919

2020
method_body = Truffle::Graal.copy_captured_locals -> *args, &block do
2121
if argc == -1 # (int argc, VALUE *argv, VALUE obj)
22-
args = [args.size, Truffle::CExt.RARRAY_PTR(args), Truffle::CExt.rb_tr_wrap(self)]
22+
args = [args.size, Truffle::CExt.RARRAY_PTR(args), Truffle.invoke_primitive(:cext_wrap, self)]
2323
elsif argc == -2 # (VALUE obj, VALUE rubyArrayArgs)
24-
args = [Truffle::CExt.rb_tr_wrap(self), Truffle::CExt.rb_tr_wrap(args)]
24+
args = [Truffle.invoke_primitive(:cext_wrap, self), Truffle.invoke_primitive(:cext_wrap, args)]
2525
elsif argc >= 0 # (VALUE obj); (VALUE obj, VALUE arg1); (VALUE obj, VALUE arg1, VALUE arg2); ...
2626
if args.size != argc
2727
raise ArgumentError, "wrong number of arguments (given #{args.size}, expected #{argc})"
2828
end
29-
args = [Truffle::CExt.rb_tr_wrap(self), *args.map! { |arg| Truffle::CExt.rb_tr_wrap(arg) }]
29+
args = [Truffle.invoke_primitive(:cext_wrap, self), *args.map! { |arg| Truffle.invoke_primitive(:cext_wrap, arg) }]
3030
end
3131

3232
# Using raw execute instead of #call here to avoid argument conversion
33-
Truffle::CExt.push_preserving_frame
34-
begin
35-
# We must call explicitly with the block argument if given
36-
# here so that the `rb_block_*` functions will be able to find
37-
# it by walking the stack.
38-
if block
39-
Truffle::CExt.rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex, function, args, &block))
40-
else
41-
Truffle::CExt.rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex, function, args))
42-
end
43-
ensure
44-
Truffle::CExt.pop_preserving_frame
45-
end
33+
34+
# We must set block argument if given here so that the
35+
# `rb_block_*` functions will be able to find it by walking the
36+
# stack.
37+
Truffle.invoke_primitive(:cext_unwrap, Truffle.invoke_primitive(:call_with_c_mutex_and_frame, function, args, block))
4638
end
4739

4840
mod.define_method(name, method_body)
@@ -51,17 +43,18 @@ def rb_define_method(mod, name, function, argc)
5143
private
5244

5345
def rb_iterate_call_block(callback, block_arg, callback_arg, &block)
54-
rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex, callback, [rb_tr_wrap(block_arg), rb_tr_wrap(callback_arg)]))
46+
rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex_and_frame, callback, [rb_tr_wrap(block_arg), rb_tr_wrap(callback_arg)], block))
5547
end
5648

5749
def call_with_thread_locally_stored_block(function, *args, &block)
5850
# MRI puts the block to a thread local th->passed_block and later rb_funcall reads it,
5951
# we have to do the same
6052
# TODO (pitr-ch 14-Dec-2017): This is fixed just for rb_iterate with a rb_funcall in it combination
53+
6154
previous_block = Thread.current[:__C_BLOCK__]
6255
begin
6356
Thread.current[:__C_BLOCK__] = block
64-
rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex, function, args.map! { |arg| Truffle::CExt.rb_tr_wrap(arg) }, &block))
57+
rb_tr_unwrap(Truffle.invoke_primitive(:call_with_c_mutex_and_frame, function, args.map! { |arg| Truffle.invoke_primitive(:cext_wrap, arg) }, block))
6558
ensure
6659
Thread.current[:__C_BLOCK__] = previous_block
6760
end

src/main/java/org/truffleruby/cext/CExtNodes.java

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,12 @@
4444
import org.truffleruby.builtins.Primitive;
4545
import org.truffleruby.builtins.PrimitiveArrayArgumentsNode;
4646
import org.truffleruby.builtins.YieldingCoreMethodNode;
47+
import org.truffleruby.cext.CExtNodesFactory.CallCWithMutexNodeFactory;
4748
import org.truffleruby.cext.CExtNodesFactory.StringToNativeNodeGen;
49+
import org.truffleruby.cext.CExtNodesFactory.CallCWithMutexNodeFactory.CallCWithMutexNodeGen;
4850
import org.truffleruby.core.CoreLibrary;
4951
import org.truffleruby.core.MarkingServiceNodes;
52+
import org.truffleruby.core.MarkingService.ExtensionCallStack;
5053
import org.truffleruby.core.array.ArrayHelpers;
5154
import org.truffleruby.core.array.ArrayOperationNodes;
5255
import org.truffleruby.core.array.ArrayStrategy;
@@ -116,6 +119,8 @@ public class CExtNodes {
116119
@Primitive(name = "call_with_c_mutex")
117120
public abstract static class CallCWithMutexNode extends PrimitiveArrayArgumentsNode {
118121

122+
public abstract Object execute(TruffleObject receiverm, DynamicObject argsArray);
123+
119124
@Specialization
120125
public Object callCWithMutex(TruffleObject receiver, DynamicObject argsArray,
121126
@Cached("create()") ArrayToObjectArrayNode arrayToObjectArrayNode,
@@ -155,6 +160,26 @@ private Object execute(TruffleObject receiver, Object[] args, Node executeNode,
155160

156161
}
157162

163+
@ImportStatic(Message.class)
164+
@Primitive(name = "call_with_c_mutex_and_frame")
165+
public abstract static class CallCWithMuteAndFramexNode extends PrimitiveArrayArgumentsNode {
166+
167+
@Child protected CallCWithMutexNode callCextNode = CallCWithMutexNodeFactory.create(EMPTY_ARRAY);
168+
169+
@Specialization
170+
public Object callCWithMutex(VirtualFrame frame, TruffleObject receiver, DynamicObject argsArray, DynamicObject block,
171+
@Cached("create()") MarkingServiceNodes.GetMarkerThreadLocalDataNode getDataNode) {
172+
ExtensionCallStack extensionStack = getDataNode.execute(frame).getExtensionCallStack();
173+
extensionStack.push(block);
174+
175+
try {
176+
return callCextNode.execute(receiver, argsArray);
177+
} finally {
178+
extensionStack.pop();
179+
}
180+
}
181+
}
182+
158183
@ImportStatic(Message.class)
159184
@Primitive(name = "call_without_c_mutex")
160185
public abstract static class CallCWithoutMutexNode extends PrimitiveArrayArgumentsNode {
@@ -590,31 +615,11 @@ public DynamicObject rbStrResize(DynamicObject string, int newByteLength,
590615
@CoreMethod(names = "rb_block_proc", onSingleton = true)
591616
public abstract static class BlockProcNode extends CoreMethodArrayArgumentsNode {
592617

593-
// TODO (pitr-ch 04-Dec-2017): needs optimising
594-
@TruffleBoundary
595618
@Specialization
596-
public DynamicObject blockProc() {
597-
return Truffle.getRuntime().iterateFrames(frameInstance -> {
598-
final Node callNode = frameInstance.getCallNode();
599-
600-
if (callNode != null) {
601-
final RootNode rootNode = callNode.getRootNode();
602-
// Skip Ruby frames in cext.rb file since they are implementing methods which are implemented
603-
// with C in MRI, and therefore are also implicitly skipped when when looking up the block passed
604-
// to a C API function.
605-
if (rootNode instanceof RubyRootNode &&
606-
rootNode.getSourceSection().isAvailable() &&
607-
!rootNode.getSourceSection().getSource().getName().endsWith("truffle/cext.rb")) {
608-
609-
final DynamicObject block = RubyArguments.getBlock(frameInstance.getFrame(FrameAccess.READ_ONLY));
610-
return block == null ? nil() : block;
611-
}
612-
}
613-
614-
return null;
615-
});
619+
public DynamicObject block(VirtualFrame frame,
620+
@Cached("create()") MarkingServiceNodes.GetMarkerThreadLocalDataNode getDataNode) {
621+
return getDataNode.execute(frame).getExtensionCallStack().getBlock();
616622
}
617-
618623
}
619624

620625
@CoreMethod(names = "rb_check_frozen", onSingleton = true, required = 1)
@@ -1355,8 +1360,8 @@ public DynamicObject newManagedStruct(Object type) {
13551360

13561361
}
13571362

1358-
@CoreMethod(names = "rb_tr_wrap", onSingleton = true, required = 1)
1359-
public abstract static class WrapValueNode extends CoreMethodArrayArgumentsNode {
1363+
@Primitive(name = "cext_wrap", needsSelf = false)
1364+
public abstract static class WrapValueNode extends PrimitiveArrayArgumentsNode {
13601365

13611366
@Specialization
13621367
public TruffleObject wrapInt(Object value,
@@ -1369,8 +1374,8 @@ protected WrapNode createWrapNode() {
13691374
}
13701375
}
13711376

1372-
@CoreMethod(names = "rb_tr_unwrap", onSingleton = true, required = 1)
1373-
public abstract static class UnwrapValueNode extends CoreMethodArrayArgumentsNode {
1377+
@Primitive(name = "cext_unwrap", needsSelf = false)
1378+
public abstract static class UnwrapValueNode extends PrimitiveArrayArgumentsNode {
13741379

13751380
@Specialization
13761381
public Object unwrap(TruffleObject value,
@@ -1520,24 +1525,24 @@ protected void addObjectToMarkingService(DynamicObject object, DynamicObject mar
15201525
}
15211526
}
15221527

1523-
@CoreMethod(names = "push_preserving_frame", onSingleton = true, required = 0)
1528+
@CoreMethod(names = "push_extension_call_frame", onSingleton = true, required = 1)
15241529
public abstract static class PushPreservingFrame extends CoreMethodArrayArgumentsNode {
15251530

15261531
@Specialization
1527-
public DynamicObject pushFrame(VirtualFrame frame,
1532+
public DynamicObject pushFrame(VirtualFrame frame, DynamicObject block,
15281533
@Cached("create()") MarkingServiceNodes.GetMarkerThreadLocalDataNode getDataNode) {
1529-
getDataNode.execute(frame).getPreservationStack().push();
1534+
getDataNode.execute(frame).getExtensionCallStack().push(block);
15301535
return nil();
15311536
}
15321537
}
15331538

1534-
@CoreMethod(names = "pop_preserving_frame", onSingleton = true, required = 0)
1539+
@CoreMethod(names = "pop_extension_call_frame", onSingleton = true, required = 0)
15351540
public abstract static class PopPreservingFrame extends CoreMethodArrayArgumentsNode {
15361541

15371542
@Specialization
15381543
public DynamicObject popFrame(VirtualFrame frame,
15391544
@Cached("create()") MarkingServiceNodes.GetMarkerThreadLocalDataNode getDataNode) {
1540-
getDataNode.execute(frame).getPreservationStack().pop();
1545+
getDataNode.execute(frame).getExtensionCallStack().pop();
15411546
return nil();
15421547
}
15431548
}

0 commit comments

Comments
 (0)