1 assert_equal '2022', %q{
2 def contrivance(hash, key)
3 # Expect this to compile to an `opt_aref`.
6 # The [] call above tracks that the `hash` local has a VALUE that
7 # is a heap pointer and the guard for the Kernel#itself call below
8 # doesn't check that it's a heap pointer VALUE.
10 # As you can see from the crash, the call to rb_hash_aref() can set the
11 # `hash` local, making eliding the heap object guard unsound.
15 # This is similar to ->(recv, mid) { send(recv, mid).local_variable_set(...) }.
16 # By composing we avoid creating new Ruby frames and so sending :binding
17 # captures the environment of the frame that does the missing key lookup.
18 # We use it to capture the environment inside of `contrivance`.
20 Kernel.instance_method(:send).method(:bind_call).to_proc >>
21 ->(binding) { binding.local_variable_set(:hash, 2022) }
22 special_missing = Hash.new(&cap_then_set)
24 # Make YJIT speculate that it's a hash and generate code
25 # that calls rb_hash_aref().
26 contrivance({}, :warmup)
27 contrivance({}, :warmup)
29 contrivance(special_missing, :binding)
32 assert_equal '18374962167983112447', %q{
33 # regression test for incorrectly discarding 32 bits of a pointer when it
34 # comes to default values.
35 def large_literal_default(n: 0xff00_fabcafe0_00ff)
47 assert_normal_exit %q{
48 # regression test for a leak caught by an asert on --yjit-call-threshold=2
51 eval("def foo = [#{(['Foo,']*256).join}]")
56 Object.send(:remove_const, :Foo)
59 assert_equal '[nil, nil, nil, nil, nil, nil]', %q{
60 [NilClass, TrueClass, FalseClass, Integer, Float, Symbol].each do |klass|
61 klass.class_eval("def foo = @foo")
64 [nil, true, false, 0xFABCAFE, 0.42, :cake].map do |instance|
71 # This is a regression test for incomplete invalidation from
72 # opt_setinlinecache. This test might be brittle, so
73 # feel free to remove it in the future if it's too annoying.
74 # This test assumes --yjit-call-threshold=2.
81 def pin_self_type_then_foo
100 foo_method = M.instance_method(:foo)
103 return # comment this out to get printouts
105 $stderr.puts RubyVM::YJIT.disasm(foo_method)
109 2.times { 42.only_ints }
111 dbg["There should be two versions of getinlineache"]
117 dbg["There should be no getinlinecaches"]
121 rescue NameError => err
122 _ = "caught name error #{err}"
125 dbg["There should be one version of getinlineache"]
128 Sub.new.pin_self_type_then_foo
130 _ = 'second specialization'
133 dbg["There should be two versions of getinlineache"]
139 dbg["There should still be two versions of getinlineache"]
143 dbg["There should be no getinlinecaches"]
145 # Find name of the first VM instruction in M#foo.
146 insns = RubyVM::InstructionSequence.of(foo_method).to_a
147 if defined?(RubyVM::YJIT.blocks_for) && (insns.last.find { Array === _1 }&.first == :opt_getinlinecache)
148 RubyVM::YJIT.blocks_for(RubyVM::InstructionSequence.of(foo_method))
149 .filter { _1.iseq_start_index == 0 }.count
155 # Check that frozen objects are respected
156 assert_equal 'great', %q{
174 foo.bar == 1 ? "great" : "NG"
177 # Check that global variable set works
178 assert_equal 'string', %q{
186 # Check that exceptions work when setting global variables
187 assert_equal 'rescued', %q{
195 trace_var(:$var) { raise }
199 # Check that global variables work
200 assert_equal 'string', %q{
210 # Check that exceptions work when getting global variable
211 assert_equal 'rescued', %q{
229 # Check that global tracepoints work
230 assert_equal 'true', %q{
241 tp = TracePoint.new(:return) { |event|
242 if event.method_id == :foo
252 # Check that local tracepoints work
253 assert_equal 'true', %q{
264 tp = TracePoint.new(:return) { |_| called = true }
265 tp.enable(target: method(:foo))
271 # Make sure that optional param methods return the correct value
272 assert_equal '1', %q{
277 # Warm the JIT with a 0 param call
283 assert_equal 'array', %q{
301 assert_equal '2', %q{
311 assert_equal '12', %q{
321 assert_equal '3', %q{
330 # BOP redefined methods work when JIT compiled
331 assert_equal 'false', %q{
347 # BOP redefinition works on Integer#<
348 assert_equal 'false', %q{
365 # Putobject, less-than operator, fixnums
366 assert_equal '2', %q{
367 def check_index(index)
368 if 0x40000000 < index
369 raise "wat? #{index}"
377 # foo leaves a temp on the stack before the call
378 assert_equal '6', %q{
391 # Method with one arguments
392 # foo leaves a temp on the stack before the call
393 assert_equal '7', %q{
406 # Method with two arguments
407 # foo leaves a temp on the stack before the call
408 assert_equal '0', %q{
421 # Passing argument types to callees
422 assert_equal '8.5', %q{
435 # Recursive Ruby-to-Ruby calls
436 assert_equal '21', %q{
442 return fib(n-1) + fib(n-2)
448 # Ruby-to-Ruby call and C call
449 assert_normal_exit %q{
463 assert_equal '42', %q{
469 alias method_b method_a
486 # Method aliasing with method from parent class
487 assert_equal '777', %q{
495 alias method_b method_a
508 # The hash method is a C function and uses the self argument
509 assert_equal 'true', %q{
519 # Method redefinition (code invalidation) test
520 assert_equal '1', %q{
526 def alias_then_hash(klass, method_to_redefine)
527 # Redefine the method to be ret1
528 klass.alias_method(method_to_redefine, :ret1)
538 # Redefine the bar method
539 instance.alias_then_hash(klass, :bar)
541 # Redefine the hash method to be ret1
542 retval = instance.alias_then_hash(klass, :hash)
550 # Code invalidation and opt_getinlinecache
551 assert_normal_exit %q{
554 # Uses the class constant Foo
555 def use_constant(arg)
561 i.itself # make it remember that i is on-heap
567 use_constant(Foo.new)
568 class Jo; end # bump global constant state
572 # Method redefinition (code invalidation) and GC
573 assert_equal '7', %q{
595 # Method redefinition with two block versions
596 assert_equal '7', %q{
602 return ((n < 5)? 5:false), bar()
620 # Method redefinition while the method is on the stack
621 assert_equal '[777, 1]', %q{
628 # Redefine the global foo
629 eval("def foo; 1; end", TOPLEVEL_BINDING)
635 # But we will return to the original foo,
636 # which remains alive because it's on the stack
639 # Must produce [777, 1]
643 # Test for GC safety. Don't invalidate dead iseqs.
644 assert_normal_exit %q{
662 # test setinstancevariable on extended objects
663 assert_equal '1', %q{
682 # test setinstancevariable on embedded objects
683 assert_equal '1', %q{
698 # test setinstancevariable after extension
699 assert_equal '[10, 11, 12, 13, 1]', %q{
715 [@foo1, @foo2, @foo3, @foo4, @one]
727 # test setinstancevariable on frozen object
728 assert_equal 'object was not modified', %q{
743 "object was not modified"
747 # Test getinstancevariable and inline caches
748 assert_equal '6', %q{
769 # Test that getinstancevariable codegen checks for extended table size
770 assert_equal "nil\n", %q{
779 10.times { other.instance_variable_set(:"@otr#{_1}", 'value') }
780 1001.times { ins.instance_variable_set(:"@ins#{_1}", 'value') }
789 # Test that opt_aref checks the class of the receiver
790 assert_equal 'special', %q{
806 # Test that object references in generated code get marked and moved
807 assert_equal "good", %q{
820 GC.verify_compaction_references(double_heap: true, toward: :empty)
821 rescue NotImplementedError
822 # in case compaction isn't supported
828 # Test polymorphic getinstancevariable. T_OBJECT -> T_STRING
829 assert_equal 'ok', %q{
830 @hello = @h1 = @h2 = @h3 = @h4 = 'ok'
832 str.instance_variable_set(:@hello, 'ok')
844 # Test polymorphic getinstancevariable, two different classes
845 assert_equal 'ok', %q{
856 class Extended < Embedded
858 @v1 = @v2 = @v3 = @v4 = @ivar = 'ok'
863 extend = Extended.new
871 # Test megamorphic getinstancevariable
872 assert_equal 'ok', %q{
873 parent = Class.new do
875 @hello = @h1 = @h2 = @h3 = @h4 = 'ok'
883 subclasses = 300.times.map { Class.new(parent) }
884 subclasses.each { _1.new.get }
888 # Test polymorphic opt_aref. array -> hash
889 assert_equal '[42, :key]', %q{
894 index([], 0) # get over compilation threshold
902 # Test polymorphic opt_aref. hash -> array -> custom class
903 assert_equal '[nil, nil, :custom]', %q{
913 index({}, 0) # get over compilation threshold
922 # Test polymorphic opt_aref. array -> custom class
923 assert_equal '[42, :custom]', %q{
933 index([], 0) # get over compilation threshold
941 # Test custom hash method with opt_aref
942 assert_equal '[nil, :ok]', %q{
960 # Test default value block for Hash with opt_aref
961 assert_equal '[42, :default]', %q{
966 h = Hash.new { :default }
975 # A regression test for making sure cfp->sp is proper when
976 # hitting stubs. See :stub-sp-flush:
977 assert_equal 'ok', %q{
988 # This hits a stub with sp_offset > 0
994 # Test polymorphic callsite, cfunc -> iseq
995 assert_equal '[Cfunc, Iseq]', %q{
996 public def call_itself
997 itself # the polymorphic callsite
1008 call_itself # cross threshold
1010 [Cfunc.call_itself, Iseq.call_itself]
1013 # Test polymorphic callsite, iseq -> cfunc
1014 assert_equal '[Iseq, Cfunc]', %q{
1015 public def call_itself
1016 itself # the polymorphic callsite
1027 call_itself # cross threshold
1029 [Iseq.call_itself, Cfunc.call_itself]
1032 # attr_reader method
1033 assert_equal '[100, 299]', %q{
1043 @bar = @jojo = @as = @sdfsdf = @foo = 299
1058 [bar(ins), bar(oth)]
1061 # get ivar on object, then on hash
1062 assert_equal '[42, 100]', %q{
1088 # get ivar on String
1089 assert_equal '[nil, nil, 42, 42]', %q{
1090 # @foo to exercise the getinstancevariable instruction
1096 get_foo # compile it for the top level object
1108 str.instance_variable_set(:@foo, 42)
1110 [getter, insn, str.foo, str.get_foo]
1117 # splatting an empty array on a getter
1118 assert_equal '42', %q{
1132 # getinstancevariable on Symbol
1133 assert_equal '[nil, nil]', %q{
1134 # @foo to exercise the getinstancevariable instruction
1139 dyn_sym = ("a" + "b").to_sym
1146 [dyn_sym.get_foo, sym.get_foo]
1149 # attr_reader on Symbol
1150 assert_equal '[nil, nil]', %q{
1159 dyn_sym = ("a" + "b").to_sym
1166 [dyn_sym.get_foo, sym.get_foo]
1169 # passing too few arguments to method with optional parameters
1170 assert_equal 'raised', %q{
1182 rescue ArgumentError
1187 # passing too many arguments to method with optional parameters
1188 assert_equal 'raised', %q{
1200 rescue ArgumentError
1205 # test calling Ruby method with a block
1206 assert_equal '[1, 2, 42]', %q{
1219 # test calling C method with a block
1220 assert_equal '[42, 42]', %q{
1221 def use(array, initial)
1222 array.reduce(initial) { |a, b| a + b }
1226 [use([2, 2], 38), use([14, 14, 14], 0)]
1229 # test calling block param
1230 assert_equal '[1, 2, 42]', %q{
1235 [foo {1}, foo {2}, foo {42}]
1238 # test calling block param failing
1239 assert_equal '42', %q{
1248 rescue NoMethodError => e
1249 42 if nil == e.receiver
1253 # test calling method taking block param
1254 assert_equal '[Proc, 1, 2, 3, Proc]', %q{
1255 def three(a, b, c, &block)
1256 [a, b, c, block.class]
1274 [use_zero] + use_three
1277 # test building empty array
1278 assert_equal '[]', %q{
1287 # test building array of one element
1288 assert_equal '[5]', %q{
1297 # test building array of several element
1298 assert_equal '[5, 5, 5, 5, 5]', %q{
1300 [val, val, val, val, val]
1307 # test building empty hash
1308 assert_equal '{}', %q{
1317 # test building hash with values
1318 assert_equal '{:foo=>:bar}', %q{
1327 # test string interpolation with known types
1328 assert_equal 'foobar', %q{
1339 # test string interpolation with unknown types
1340 assert_equal 'foobar', %q{
1341 def make_str(foo, bar)
1345 make_str("foo", "bar")
1346 make_str("foo", "bar")
1349 # test string interpolation with known non-strings
1350 assert_equal 'foo123', %q{
1361 # test string interpolation with unknown non-strings
1362 assert_equal 'foo123', %q{
1363 def make_str(foo, bar)
1367 make_str("foo", 123)
1368 make_str("foo", 123)
1371 # test string interpolation with overridden to_s
1372 assert_equal 'foo', %q{
1388 # test invokebuiltin as used in struct assignment
1389 assert_equal '123', %q{
1394 struct = Struct.new(:foo)
1400 # test invokebuiltin_delegate as used inside Dir.open
1401 assert_equal '.', %q{
1410 # test invokebuiltin_delegate_leave in method called from jit
1411 assert_normal_exit %q{
1420 # test invokebuiltin_delegate_leave in method called from cfunc
1421 assert_normal_exit %q{
1430 # defining TrueClass#!
1431 assert_equal '[false, false, :ok]', %q{
1450 # defining FalseClass#!
1451 assert_equal '[true, true, :ok]', %q{
1470 # defining NilClass#!
1471 assert_equal '[true, true, :ok]', %q{
1490 # polymorphic opt_not
1491 assert_equal '[true, true, false, false, false, false, false]', %q{
1497 [foo(nil), foo(false), foo(true), foo([]), foo(0), foo(4.2), foo(:sym)]
1500 # getlocal with 2 levels
1501 assert_equal '7', %q{
1514 # test pattern matching
1515 assert_equal '[:ok, :ok]', %q{
1517 def destructure_keys
1522 pattern_match = ->(i) do
1531 [{}, C.new].map(&pattern_match)
1534 # Call to object with singleton
1535 assert_equal '123', %q{
1549 # Call method on an object that has a non-material
1551 # TODO: assert that it takes no side exits? This
1552 # test case revealed that we were taking exits unnecessarily.
1553 assert_normal_exit %q{
1558 o = Object.new.singleton_class
1563 # Call to singleton class
1564 assert_equal '123', %q{
1579 # invokesuper edge case
1580 assert_equal '[:A, [:A, :B]]', %q{
1586 def foo = [:A, super()]
1590 A.new.foo # compile A#foo
1593 define_method(:bar, A.instance_method(:foo))
1599 # Same invokesuper bytecode, multiple destinations
1600 assert_equal '[:Forward, :SecondTerminus]', %q{
1605 module SecondTerminus
1606 def foo = :SecondTerminus
1611 def foo = [:Forward, super]
1615 include SecondTerminus
1631 # A.ancestors.take(5) == [A, Forward, Terminus, B, Forward, SecondTerminus]
1636 # invokesuper calling into itself
1637 assert_equal '[:B, [:B, :m]]', %q{
1644 def foo = [:B, super]
1648 ins.singleton_class # materialize the singleton class
1652 ins.singleton_class.define_method(:bar, B.instance_method(:foo))
1656 # invokesuper changed ancestor
1657 assert_equal '[:A, [:M, :B]]', %q{
1683 # invokesuper changed ancestor via prepend
1684 assert_equal '[:A, [:M, :B]]', %q{
1710 # invokesuper replaced method
1711 assert_equal '[:A, :Btwo]', %q{
1736 assert_equal '[true, false]', %q{
1744 [is_odd(123), is_odd(456)]
1748 assert_equal '[true, false]', %q{
1753 bignum = 99999999999999999999
1757 [is_odd(bignum), is_odd(bignum+1)]
1760 # Call to fixnum and bignum
1761 assert_equal '[true, false, true, false]', %q{
1766 bignum = 99999999999999999999
1772 [is_odd(123), is_odd(456), is_odd(bignum), is_odd(bignum+1)]
1775 # Call to static and dynamic symbol
1776 assert_equal 'bar', %q{
1783 to_string((-"bar").to_sym)
1784 to_string((-"bar").to_sym)
1787 # Call to flonum and heap float
1788 assert_equal '[nil, nil, nil, 1]', %q{
1806 assert_equal '[1, 2, 3, 4, 5]', %q{
1815 assert_equal '[1, 1, 2, 1, 2, 3]', %q{
1830 assert_equal '[1, 1]', %q{
1831 def expandarray_useless_splat
1840 expandarray_useless_splat
1841 expandarray_useless_splat
1844 assert_equal '[:not_heap, nil, nil]', %q{
1845 def expandarray_not_heap
1850 expandarray_not_heap
1851 expandarray_not_heap
1854 assert_equal '[:not_array, nil, nil]', %q{
1855 def expandarray_not_array(obj)
1865 expandarray_not_array(obj)
1866 expandarray_not_array(obj)
1869 assert_equal '[1, 2, nil]', %q{
1870 def expandarray_rhs_too_small
1875 expandarray_rhs_too_small
1876 expandarray_rhs_too_small
1879 assert_equal '[1, [2]]', %q{
1880 def expandarray_splat
1889 assert_equal '2', %q{
1890 def expandarray_postarg
1899 assert_equal '10', %q{
1902 obj.define_singleton_method(:to_ary) { val = 10; [] }
1904 def expandarray_always_call_to_ary(object)
1908 expandarray_always_call_to_ary(obj)
1909 expandarray_always_call_to_ary(obj)
1914 # regression test of local type change
1915 assert_equal '1.1', %q{
1918 baz, quux = quux, nil
1927 # test enabling a line TracePoint in a C method call
1928 assert_equal '[[:line, true]]', %q{
1930 events.instance_variable_set(
1932 TracePoint.new(:line) { |tp| events << [tp.event, tp.lineno] if tp.path == __FILE__ }
1938 # Stay in generated code while enabling tracing
1939 def events.compiled(obj)
1941 @tp.disable; __LINE__
1944 line = events.compiled(events)
1945 events[0][-1] = (events[0][-1] == line)
1950 # test enabling a c_return TracePoint in a C method call
1951 assert_equal '[[:c_return, :String, :string_alias, "events_to_str"]]', %q{
1953 events.instance_variable_set(:@tp, TracePoint.new(:c_return) { |tp| events << [tp.event, tp.method_id, tp.callee_id, tp.return_value] })
1955 @tp.enable; 'events_to_str'
1958 # Stay in generated code while enabling tracing
1959 alias string_alias String
1960 def events.compiled(obj)
1965 events.compiled(events)
1970 # test enabling a TracePoint that targets a particular line in a C method call
1971 assert_equal '[true]', %q{
1973 events.instance_variable_set(:@tp, TracePoint.new(:line) { |tp| events << tp.lineno })
1975 @tp.enable(target: method(:compiled))
1979 # Stay in generated code while enabling tracing
1980 def events.compiled(obj)
1985 line = events.compiled(events)
1986 events[0] = (events[0] == line)
1991 # test enabling tracing in the middle of splatarray
1992 assert_equal '[true]', %q{
1995 obj.instance_variable_set(:@tp, TracePoint.new(:line) { |tp| events << tp.lineno })
1997 @tp.enable(target: method(:compiled))
2001 # Enable tracing in the middle of the splatarray instruction
2002 def obj.compiled(obj)
2008 line = obj.compiled(obj)
2009 events[0] = (events[0] == line)
2014 # test enabling tracing in the middle of opt_aref. Different since the codegen
2015 # for it ends in a jump.
2016 assert_equal '[true]', %q{
2017 def lookup(hash, tp)
2019 tp.disable; __LINE__
2023 tp = TracePoint.new(:line) { lines << _1.lineno if _1.path == __FILE__ }
2028 enable_tracing_on_missing = Hash.new { tp.enable }
2030 expected_line = lookup(enable_tracing_on_missing, tp)
2032 lines[0] = true if lines[0] == expected_line
2037 # test enabling c_call tracing before compiling
2038 assert_equal '[[:c_call, :itself]]', %q{
2039 def shouldnt_compile
2044 tp = TracePoint.new(:c_call) { |tp| events << [tp.event, tp.method_id] }
2046 # assume first call compiles
2047 tp.enable { shouldnt_compile }
2052 # test enabling c_return tracing before compiling
2053 assert_equal '[[:c_return, :itself, main]]', %q{
2054 def shouldnt_compile
2059 tp = TracePoint.new(:c_return) { |tp| events << [tp.event, tp.method_id, tp.return_value] }
2061 # assume first call compiles
2062 tp.enable { shouldnt_compile }
2067 # test enabling tracing for a suspended fiber
2068 assert_equal '[[:return, 42]]', %q{
2075 tp = TracePoint.new(:return) { events << [_1.event, _1.return_value] }
2076 # assume first call compiles
2077 fiber = Fiber.new { traced_method }
2079 tp.enable(target: method(:traced_method))
2085 # test compiling on non-tracing ractor then running on a tracing one
2086 assert_equal '[:itself]', %q{
2092 tracing_ractor = Ractor.new do
2095 tp = TracePoint.new(:c_call) { events << _1.method_id }
2099 # 3: run compiled method on tracing ractor
2110 # 2: compile on non tracing ractor
2117 # Try to hit a lazy branch stub while another ractor enables tracing
2118 assert_equal '42', %q{
2128 ractor = Ractor.new do
2134 tp = TracePoint.new(:line) { itself }
2141 # Test equality with changing types
2142 assert_equal '[true, false, false, false]', %q{
2155 # Redefined String eq
2156 assert_equal 'true', %q{
2171 # Redefined Integer eq
2172 assert_equal 'true', %q{
2187 # aset on array with invalid key
2188 assert_normal_exit %q{
2197 # test ractor exception on when setting ivar
2198 assert_equal '42', %q{
2205 rescue Ractor::IsolationError
2214 Ractor.new { A.foo }.take
2217 assert_equal '["plain", "special", "sub", "plain"]', %q{
2225 special = String.new("special")
2226 special.singleton_class
2231 foo(Sub.new("sub")),
2236 assert_equal '["sub", "sub"]', %q{
2247 sub = Sub.new("sub")
2249 [foo(sub), foo(sub)]
2252 assert_equal '[1]', %q{
2257 5.times.map { kwargs(value: 1) }.uniq
2260 assert_equal '[:ok]', %q{
2265 5.times.map { kwargs() rescue :ok }.uniq
2268 assert_equal '[:ok]', %q{
2269 def kwargs(a:, b: nil)
2273 5.times.map { kwargs(b: 123) rescue :ok }.uniq
2276 assert_equal '[[1, 2]]', %q{
2277 def kwargs(left:, right:)
2283 kwargs(left: 1, right: 2),
2284 kwargs(right: 2, left: 1)
2289 assert_equal '[[1, 2]]', %q{
2290 def kwargs(lead, kwarg:)
2294 5.times.map { kwargs(1, kwarg: 2) }.uniq
2297 # optional and keyword args
2298 assert_equal '[[1, 2, 3]]', %q{
2299 def opt_and_kwargs(a, b=2, c: nil)
2303 5.times.map { opt_and_kwargs(1, c: 3) }.uniq
2306 assert_equal '[[1, 2, 3]]', %q{
2307 def opt_and_kwargs(a, b=nil, c: nil)
2311 5.times.map { opt_and_kwargs(1, 2, c: 3) }.uniq
2315 assert_equal '[[1, nil, 2]]', %q{
2316 def opt_and_kwargs(a = {}, b: nil, c: nil)
2320 5.times.map { opt_and_kwargs(1, c: 2) }.uniq
2323 assert_equal '[[{}, nil, 1]]', %q{
2324 def opt_and_kwargs(a = {}, b: nil, c: nil)
2328 5.times.map { opt_and_kwargs(c: 1) }.uniq
2331 # leading and keyword arguments are swapped into the right order
2332 assert_equal '[[1, 2, 3, 4, 5, 6]]', %q{
2333 def kwargs(five, six, a:, b:, c:, d:)
2334 [a, b, c, d, five, six]
2339 kwargs(5, 6, a: 1, b: 2, c: 3, d: 4),
2340 kwargs(5, 6, a: 1, b: 2, d: 4, c: 3),
2341 kwargs(5, 6, a: 1, c: 3, b: 2, d: 4),
2342 kwargs(5, 6, a: 1, c: 3, d: 4, b: 2),
2343 kwargs(5, 6, a: 1, d: 4, b: 2, c: 3),
2344 kwargs(5, 6, a: 1, d: 4, c: 3, b: 2),
2345 kwargs(5, 6, b: 2, a: 1, c: 3, d: 4),
2346 kwargs(5, 6, b: 2, a: 1, d: 4, c: 3),
2347 kwargs(5, 6, b: 2, c: 3, a: 1, d: 4),
2348 kwargs(5, 6, b: 2, c: 3, d: 4, a: 1),
2349 kwargs(5, 6, b: 2, d: 4, a: 1, c: 3),
2350 kwargs(5, 6, b: 2, d: 4, c: 3, a: 1),
2351 kwargs(5, 6, c: 3, a: 1, b: 2, d: 4),
2352 kwargs(5, 6, c: 3, a: 1, d: 4, b: 2),
2353 kwargs(5, 6, c: 3, b: 2, a: 1, d: 4),
2354 kwargs(5, 6, c: 3, b: 2, d: 4, a: 1),
2355 kwargs(5, 6, c: 3, d: 4, a: 1, b: 2),
2356 kwargs(5, 6, c: 3, d: 4, b: 2, a: 1),
2357 kwargs(5, 6, d: 4, a: 1, b: 2, c: 3),
2358 kwargs(5, 6, d: 4, a: 1, c: 3, b: 2),
2359 kwargs(5, 6, d: 4, b: 2, a: 1, c: 3),
2360 kwargs(5, 6, d: 4, b: 2, c: 3, a: 1),
2361 kwargs(5, 6, d: 4, c: 3, a: 1, b: 2),
2362 kwargs(5, 6, d: 4, c: 3, b: 2, a: 1)
2367 # implicit hashes get skipped and don't break compilation
2368 assert_equal '[[:key]]', %q{
2373 5.times.map { implicit(key: :value) }.uniq
2376 # default values on keywords don't mess up argument order
2377 assert_equal '[2]', %q{
2382 def default_expression(value: default_value)
2386 5.times.map { default_expression(value: 2) }.uniq
2389 # constant default values on keywords
2390 assert_equal '[3]', %q{
2391 def default_expression(value: 3)
2395 5.times.map { default_expression }.uniq
2398 # non-constant default values on keywords
2399 assert_equal '[3]', %q{
2404 def default_expression(value: default_value)
2408 5.times.map { default_expression }.uniq
2411 # reordered optional kwargs
2412 assert_equal '[[100, 1]]', %q{
2413 def foo(capacity: 100, max: nil)
2417 5.times.map { foo(max: 1) }.uniq
2420 # invalid lead param
2421 assert_equal 'ok', %q{
2433 rescue ArgumentError => e
2438 # reordered required kwargs
2439 assert_equal '[[1, 2, 3, 4]]', %q{
2440 def foo(default1: 1, required1:, default2: 3, required2:)
2441 [default1, required1, default2, required2]
2444 5.times.map { foo(required1: 2, required2: 4) }.uniq
2447 # reordered default expression kwargs
2448 assert_equal '[[:one, :two, 3]]', %q{
2449 def foo(arg1: (1+0), arg2: (2+0), arg3: (3+0))
2453 5.times.map { foo(arg2: :two, arg1: :one) }.uniq
2457 assert_equal '[[1, 2, 3, 4]]', %q{
2458 def foo(required:, specified: 999, simple_default: 3, complex_default: "4".to_i)
2459 [required, specified, simple_default, complex_default]
2462 5.times.map { foo(specified: 2, required: 1) }.uniq
2466 assert_equal '{:foo=>123}', %q{
2468 bar.store(:value, foo: 123)
2477 assert_equal '{:foo=>123}', %q{
2479 bar.replace(foo: 123)
2487 assert_equal '{:foo=>123, :bar=>456}', %q{
2489 bar.replace(foo: 123, bar: 456)
2496 # variadic cfunc kwargs
2497 assert_equal '{:foo=>123}', %q{
2506 # optimized cfunc kwargs
2507 assert_equal 'false', %q{
2509 :foo.eql?(foo: :foo)
2516 # attr_reader on frozen object
2517 assert_equal 'false', %q{
2519 attr_reader :exception
2526 foo = Foo.new.freeze
2531 # regression test for doing kwarg shuffle before checking for interrupts
2532 assert_equal 'ok', %q{
2533 def new_media_drop(attributes:, product_drop:, context:, sources:)
2534 nil.nomethod rescue nil # force YJIT to bail to side exit
2536 [attributes, product_drop, context, sources]
2539 def load_medias(product_drop: nil, raw_medias:, context:)
2540 raw_medias.map do |raw_media|
2541 case new_media_drop(context: context, attributes: raw_media, product_drop: product_drop, sources: [])
2542 in [Hash, ProductDrop, Context, Array]
2553 def initialize(title)
2558 # Make a thread so we have thread switching interrupts
2563 load_medias(product_drop: ProductDrop.new("foo"), raw_medias: [{}, {}], context: Context.new)
2570 # regression test for tracing attr_accessor methods.
2571 assert_equal "true", %q{
2579 ar_meth = obj.method(:x)
2580 aw_meth = obj.method(:x=)
2581 aar_meth = obj.method(:y)
2582 aaw_meth = obj.method(:y=)
2584 trace = TracePoint.new(:c_call, :c_return){|tp|
2585 next if tp.path != __FILE__
2586 next if tp.method_id == :call
2589 events << [tp.event, tp.method_id, tp.callee_id]
2591 events << [tp.event, tp.method_id, tp.callee_id, tp.return_value]
2604 test_proc.call # populate call caches
2605 trace.enable(&test_proc)
2607 [:c_call, :x=, :x=],
2608 [:c_return, :x=, :x=, 1],
2610 [:c_return, :x, :x, 1],
2611 [:c_call, :x=, :y=],
2612 [:c_return, :x=, :y=, 2],
2614 [:c_return, :x, :y, 2],
2621 assert_equal '{:foo=>123}', %q{
2631 assert_equal '{:foo=>2}', %q{
2640 # block invalidation edge case
2641 assert_equal 'undef', %q{
2644 arg.times { A.remove_method(:bar) }
2653 # two consecutive sends. When bar is removed, the return address
2654 # for calling it is already on foo's control frame
2656 rescue NoMethodError
2666 # block invalidation edge case
2667 assert_equal 'ok', %q{
2671 arg.times { A.const_set(:Good, :ok) }
2680 # send followed by an opt_getinlinecache.
2681 # The return address remains on the control frame
2682 # when opt_getinlinecache is invalidated.
2692 assert_equal 'ok', %q{
2693 # test hitting a branch stub when out of memory
2705 RubyVM::YJIT.simulate_oom! if defined?(RubyVM::YJIT)
2710 assert_equal 'new', %q{
2711 # test block invalidation while out of memory
2723 RubyVM::YJIT.simulate_oom! if defined?(RubyVM::YJIT)
2732 assert_equal 'ok', %q{
2733 # Try to compile new method while OOM
2738 RubyVM::YJIT.simulate_oom! if defined?(RubyVM::YJIT)
2744 # struct aref embedded
2745 assert_equal '2', %q{
2750 S = Struct.new(:foo)
2755 # struct aref non-embedded
2756 assert_equal '4', %q{
2761 S = Struct.new(:a, :b, :c, :d, :e)
2762 foo(S.new(1,2,3,4,5))
2763 foo(S.new(1,2,3,4,5))
2766 # struct aset embedded
2767 assert_equal '123', %q{
2772 s = Struct.new(:foo).new
2774 s = Struct.new(:foo).new
2779 # struct aset non-embedded
2780 assert_equal '[1, 2, 3, 4, 5]', %q{
2789 S = Struct.new(:a, :b, :c, :d, :e)
2794 [s.a, s.b, s.c, s.d, s.e]
2797 # struct aref too many args
2798 assert_equal 'ok', %q{
2803 s = Struct.new(:foo).new
2808 # struct aset too many args
2809 assert_equal 'ok', %q{
2811 s.set_foo(123, :bad)
2814 s = Struct.new(:foo) do
2815 alias :set_foo :foo=
2821 # File.join is a cfunc accepting variable arguments as a Ruby array (argc = -2)
2822 assert_equal 'foo/bar', %q{
2824 File.join("foo", "bar")
2831 # File.join is a cfunc accepting variable arguments as a Ruby array (argc = -2)
2832 assert_equal '', %q{