# C0 coverage of each instructions # :NOTE: This is for development purpose; never consider this file as # ISeq compilation specification. begin # This library brings some additional coverage. # Not mandatory. require 'rbconfig/sizeof' rescue LoadError # OK, just skip else $FIXNUM_MAX = RbConfig::LIMITS["FIXNUM_MAX"] $FIXNUM_MIN = RbConfig::LIMITS["FIXNUM_MIN"] end fsl = { frozen_string_literal: true } # used later tests = [ # insn , expression to generate such insn [ 'nop', %q{ raise rescue true }, ], [ 'setlocal *, 0', %q{ x = true }, ], [ 'setlocal *, 1', %q{ x = nil; -> { x = true }.call }, ], [ 'setlocal', %q{ x = nil; -> { -> { x = true }.() }.() }, ], [ 'getlocal *, 0', %q{ x = true; x }, ], [ 'getlocal *, 1', %q{ x = true; -> { x }.call }, ], [ 'getlocal', %q{ x = true; -> { -> { x }.() }.() }, ], [ 'setblockparam', <<~'},', ], # { def m&b b = # here proc { true } end m { false }.call }, [ 'getblockparam', <<~'},', ], # { def m&b b # here end m { true }.call }, [ 'getblockparamproxy', <<~'},', ], # { def m&b b # here .call end m { true } }, [ 'setspecial', %q{ true if true..true }, ], [ 'getspecial', %q{ $&.nil? }, ], [ 'getspecial', %q{ $`.nil? }, ], [ 'getspecial', %q{ $'.nil? }, ], [ 'getspecial', %q{ $+.nil? }, ], [ 'getspecial', %q{ $1.nil? }, ], [ 'getspecial', %q{ $128.nil? }, ], [ 'getglobal', %q{ String === $0 }, ], [ 'getglobal', %q{ $_.nil? }, ], [ 'setglobal', %q{ $0 = "true" }, ], [ 'setinstancevariable', %q{ @x = true }, ], [ 'getinstancevariable', %q{ @x = true; @x }, ], [ 'setclassvariable', %q{ @@x = true }, ], [ 'getclassvariable', %q{ @@x = true; @@x }, ], [ 'setconstant', %q{ X = true }, ], [ 'setconstant', %q{ Object::X = true }, ], [ 'getconstant', %q{ X = true; X }, ], [ 'getconstant', %q{ X = true; Object::X }, ], [ 'getinlinecache / setinlinecache', %q{ def x; X; end; X = true; x; x; x }, ], [ 'putnil', %q{ $~ == nil }, ], [ 'putself', %q{ $~ != self }, ], [ 'putobject INT2FIX(0)', %q{ $~ != 0 }, ], [ 'putobject INT2FIX(1)', %q{ $~ != 1 }, ], [ 'putobject', %q{ $~ != -1 }, ], [ 'putobject', %q{ $~ != /x/ }, ], [ 'putobject', %q{ $~ != :x }, ], [ 'putobject', %q{ $~ != (1..2) }, ], [ 'putobject', %q{ $~ != true }, ], [ 'putobject', %q{ /(?x)/ =~ "x"; x == "x" }, ], [ 'putspecialobject', %q{ {//=>true}[//] }, ], [ 'putiseq', %q{ -> { true }.() }, ], [ 'putstring', %q{ "true" }, ], [ 'tostring / concatstrings', %q{ "#{true}" }, ], [ 'freezestring', %q{ "#{true}" }, fsl, ], [ 'freezestring', %q{ "#{true}" }, '-d', fsl, ], [ 'toregexp', %q{ /#{true}/ =~ "true" && $~ }, ], [ 'intern', %q{ :"#{true}" }, ], [ 'newarray', %q{ ["true"][0] }, ], [ 'duparray', %q{ [ true ][0] }, ], [ 'expandarray', %q{ y = [ true, false, nil ]; x, = y; x }, ], [ 'expandarray', %q{ y = [ true, false, nil ]; x, *z = y; x }, ], [ 'expandarray', %q{ y = [ true, false, nil ]; x, *z, w = y; x }, ], [ 'splatarray', %q{ x, = *(y = true), false; x }, ], [ 'concatarray', %q{ ["t", "r", *x = "u", "e"].join }, ], [ 'concatarray', <<~'},', ], # { class X; def to_a; ['u']; end; end ['t', 'r', *X.new, 'e'].join }, [ 'concatarray', <<~'},', ], # { r = false t = [true, nil] q, w, e = r, *t # here w }, [ 'newhash', %q{ x = {}; x[x] = true }, ], [ 'newhash', %q{ x = true; { x => x }[x] }, ], [ 'newrange', %q{ x = 1; [*(0..x)][0] == 0 }, ], [ 'newrange', %q{ x = 1; [*(0...x)][0] == 0 }, ], [ 'pop', %q{ def x; true; end; x }, ], [ 'dup', %q{ x = y = true; x }, ], [ 'dupn', %q{ Object::X ||= true }, ], [ 'reverse', %q{ q, (w, e), r = 1, [2, 3], 4; e == 3 }, ], [ 'swap', <<~'},', ], # { x = [[false, true]] for i, j in x # here ; end j }, [ 'topn', %q{ x, y = [], 0; x[*y], = [true, false]; x[0] }, ], [ 'setn', %q{ x, y = [], 0; x[*y] = true ; x[0] }, ], [ 'adjuststack', %q{ x = [true]; x[0] ||= nil; x[0] }, ], [ 'defined', %q{ !defined?(x) }, ], [ 'checkkeyword', %q{ def x x:rand;x end; x x: true }, ], [ 'checktype', %q{ x = true; "#{x}" }, ], [ 'checkmatch', <<~'},', ], # { x = y = true case x when false y = false when true # here y = nil end y == nil }, [ 'checkmatch', <<~'},', ], # { x, y = true, [false] case x when *y # here z = false else z = true end z }, [ 'checkmatch', <<~'},', ], # { x = false begin raise rescue # here x = true end x }, [ 'defineclass', %q{ module X; true end }, ], [ 'defineclass', %q{ X = Module.new; module X; true end }, ], [ 'defineclass', %q{ class X; true end }, ], [ 'defineclass', %q{ X = Class.new; class X; true end }, ], [ 'defineclass', %q{ X = Class.new; class Y < X; true end }, ], [ 'defineclass', %q{ X = Class.new; class << X; true end }, ], [ 'defineclass', <<~'},', ], # { X = Class.new Y = Class.new(X) class Y < X true end }, [ 'opt_send_without_block', %q{ true.to_s }, ], [ 'send', %q{ true.tap {|i| i.to_s } }, ], [ 'leave', %q{ def x; true; end; x }, ], [ 'invokesuper', <<~'},', ], # { class X < String def empty? super # here end end X.new.empty? }, [ 'invokeblock', <<~'},', ], # { def x return yield self # here end x do true end }, [ 'opt_str_freeze', %q{ 'true'.freeze }, ], [ 'opt_str_uminus', %q{ -'true' }, ], [ 'opt_str_freeze', <<~'},', ], # { class String def freeze true end end 'true'.freeze }, [ 'opt_newarray_max', %q{ [ ].max.nil? }, ], [ 'opt_newarray_max', %q{ [1, x = 2, 3].max == 3 }, ], [ 'opt_newarray_max', <<~'},', ], # { class Array def max true end end [1, x = 2, 3].max }, [ 'opt_newarray_min', %q{ [ ].min.nil? }, ], [ 'opt_newarray_min', %q{ [3, x = 2, 1].min == 1 }, ], [ 'opt_newarray_min', <<~'},', ], # { class Array def min true end end [3, x = 2, 1].min }, [ 'throw', %q{ false.tap { break true } }, ], [ 'branchif', %q{ x = nil; x ||= true }, ], [ 'branchif', %q{ x = true; x ||= nil; x }, ], [ 'branchunless', %q{ x = 1; x &&= true }, ], [ 'branchunless', %q{ x = nil; x &&= true; x.nil? }, ], [ 'branchnil', %q{ x = true; x&.to_s }, ], [ 'branchnil', %q{ x = nil; (x&.to_s).nil? }, ], [ 'jump', <<~'},', ], # { y = 1 x = if y == 0 then nil elsif y == 1 then true else nil end x }, [ 'jump', <<~'},', ], # { # ultra complicated situation: this ||= assignment only generates # 15 instructions, not including the class definition. class X; attr_accessor :x; end x = X.new x&.x ||= true # here }, [ 'once', %q{ /#{true}/o =~ "true" && $~ }, ], [ 'once', <<~'},', ], # { def once expr return /#{expr}/o # here end x = once(true); x = once(false); x = once(nil); x =~ "true" && $~ }, [ 'once', <<~'},', ], # { # recursive once def once n return %r/#{ if n == 0 true else once(n-1) # here end }/ox end x = once(128); x = once(7); x = once(16); x =~ "true" && $~ }, [ 'once', <<~'},', ], # { # inter-thread lockup situation def once n return Thread.start n do |m| Thread.pass next %r/#{ sleep m # here true }/ox end end x = once(1); y = once(0.1); z = y.value z =~ "true" && $~ }, [ 'opt_case_dispatch', %q{ case 0 when 1.1 then false else true end }, ], [ 'opt_case_dispatch', %q{ case 1.0 when 1.1 then false else true end }, ], [ 'opt_plus', %q{ 1 + 1 == 2 }, ], if defined? $FIXNUM_MAX then [ 'opt_plus', %Q{ #{ $FIXNUM_MAX } + 1 == #{ $FIXNUM_MAX + 1 } }, ] end, [ 'opt_plus', %q{ 1.0 + 1.0 == 2.0 }, ], [ 'opt_plus', %q{ x = +0.0.next_float; x + x >= x }, ], [ 'opt_plus', %q{ 't' + 'rue' }, ], [ 'opt_plus', %q{ ( ['t'] + ['r', ['u', ['e'], ], ] ).join }, ], [ 'opt_plus', %q{ Time.at(1) + 1 == Time.at(2) }, ], [ 'opt_minus', %q{ 1 - 1 == 0 }, ], if defined? $FIXNUM_MIN then [ 'opt_minus', %Q{ #{ $FIXNUM_MIN } - 1 == #{ $FIXNUM_MIN - 1 } }, ] end, [ 'opt_minus', %q{ 1.0 - 1.0 == 0.0 }, ], [ 'opt_minus', %q{ x = -0.0.prev_float; x - x == 0.0 }, ], [ 'opt_minus', %q{ ( [false, true] - [false] )[0] }, ], [ 'opt_mult', %q{ 1 * 1 == 1 }, ], [ 'opt_mult', %q{ 1.0 * 1.0 == 1.0 }, ], [ 'opt_mult', %q{ x = +0.0.next_float; x * x <= x }, ], [ 'opt_mult', %q{ ( "ruet" * 3 )[7,4] }, ], [ 'opt_div', %q{ 1 / 1 == 1 }, ], [ 'opt_div', %q{ 1.0 / 1.0 == 1.0 }, ], [ 'opt_div', %q{ x = +0.0.next_float; x / x >= x }, ], [ 'opt_div', %q{ x = 1/2r; x / x == 1 }, ], [ 'opt_mod', %q{ 1 % 1 == 0 }, ], [ 'opt_mod', %q{ 1.0 % 1.0 == 0.0 }, ], [ 'opt_mod', %q{ x = +0.0.next_float; x % x == 0.0 }, ], [ 'opt_mod', %q{ '%s' % [ true ] }, ], [ 'opt_eq', %q{ 1 == 1 }, ], [ 'opt_eq', <<~'},', ], # { class X; def == other; true; end; end X.new == true }, [ 'opt_neq', %q{ 1 != 0 }, ], [ 'opt_neq', <<~'},', ], # { class X; def != other; true; end; end X.new != true }, [ 'opt_lt', %q{ -1 < 0 }, ], [ 'opt_lt', %q{ -1.0 < 0.0 }, ], [ 'opt_lt', %q{ -0.0.prev_float < 0.0 }, ], [ 'opt_lt', %q{ ?a < ?z }, ], [ 'opt_le', %q{ -1 <= 0 }, ], [ 'opt_le', %q{ -1.0 <= 0.0 }, ], [ 'opt_le', %q{ -0.0.prev_float <= 0.0 }, ], [ 'opt_le', %q{ ?a <= ?z }, ], [ 'opt_gt', %q{ 1 > 0 }, ], [ 'opt_gt', %q{ 1.0 > 0.0 }, ], [ 'opt_gt', %q{ +0.0.next_float > 0.0 }, ], [ 'opt_gt', %q{ ?z > ?a }, ], [ 'opt_ge', %q{ 1 >= 0 }, ], [ 'opt_ge', %q{ 1.0 >= 0.0 }, ], [ 'opt_ge', %q{ +0.0.next_float >= 0.0 }, ], [ 'opt_ge', %q{ ?z >= ?a }, ], [ 'opt_ltlt', %q{ '' << 'true' }, ], [ 'opt_ltlt', %q{ ([] << 'true').join }, ], [ 'opt_ltlt', %q{ (1 << 31) == 2147483648 }, ], [ 'opt_aref', %q{ ['true'][0] }, ], [ 'opt_aref', %q{ { 0 => 'true'}[0] }, ], [ 'opt_aref', %q{ 'true'[0] == ?t }, ], [ 'opt_aset', %q{ [][0] = true }, ], [ 'opt_aset', %q{ {}[0] = true }, ], [ 'opt_aset', %q{ x = 'frue'; x[0] = 't'; x }, ], [ 'opt_aset', <<~'},', ], # { # opt_aref / opt_aset mixup situation class X; def x; {}; end; end x = X.new x&.x[true] ||= true # here }, [ 'opt_aref_with', %q{ { 'true' => true }['true'] }, ], [ 'opt_aref_with', %q{ Struct.new(:nil).new['nil'].nil? }, ], [ 'opt_aset_with', %q{ {}['true'] = true }, ], [ 'opt_aset_with', %q{ Struct.new(:true).new['true'] = true }, ], [ 'opt_length', %q{ 'true' .length == 4 }, ], [ 'opt_length', %q{ :true .length == 4 }, ], [ 'opt_length', %q{ [ 'true' ] .length == 1 }, ], [ 'opt_length', %q{ { 'true' => 1 }.length == 1 }, ], [ 'opt_size', %q{ 'true' .size == 4 }, ], [ 'opt_size', %q{ 1.size >= 4 }, ], [ 'opt_size', %q{ [ 'true' ] .size == 1 }, ], [ 'opt_size', %q{ { 'true' => 1 }.size == 1 }, ], [ 'opt_empty_p', %q{ ''.empty? }, ], [ 'opt_empty_p', %q{ [].empty? }, ], [ 'opt_empty_p', %q{ {}.empty? }, ], [ 'opt_empty_p', %q{ Queue.new.empty? }, ], [ 'opt_succ', %q{ 1.succ == 2 }, ], if defined? $FIXNUM_MAX then [ 'opt_succ',%Q{ #{ $FIXNUM_MAX }.succ == #{ $FIXNUM_MAX + 1 } }, ] end, [ 'opt_succ', %q{ '1'.succ == '2' }, ], [ 'opt_succ', %q{ x = Time.at(0); x.succ == Time.at(1) }, ], [ 'opt_not', %q{ ! false }, ], [ 'opt_neq', <<~'},', ], # { class X; def !; true; end; end ! X.new }, [ 'opt_regexpmatch1', %q{ /true/ =~ 'true' && $~ }, ], [ 'opt_regexpmatch1', <<~'},', ], # { class Regexp; def =~ other; true; end; end /true/ =~ 'true' }, [ 'opt_regexpmatch2', %q{ 'true' =~ /true/ && $~ }, ], [ 'opt_regexpmatch2', <<~'},', ], # { class String; def =~ other; true; end; end 'true' =~ /true/ }, [ 'opt_call_c_function', 'Struct.new(:x).new.x = true', ], ] # normal path tests.compact.each {|(insn, expr, *a)| assert_equal 'true', expr, insn, *a } # with trace tests.compact.each {|(insn, expr, *a)| progn = "set_trace_func(proc{})\n" + expr assert_equal 'true', progn, insn, *a }