ruby/bootstraptest/test_insns.rb

485 строки
14 KiB
Ruby

# 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
if defined? RbConfig::LIMITS
$FIXNUM_MAX = RbConfig::LIMITS["FIXNUM_MAX"]
$FIXNUM_MIN = RbConfig::LIMITS["FIXNUM_MIN"]
end
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{ class A; @@x = true; end }, ],
[ 'getclassvariable', %q{ class A; @@x = true; @@x end }, ],
[ '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 == "x" }, ],
[ 'putspecialobject', %q{ {//=>true}[//] }, ],
[ 'putstring', %q{ "true" }, ],
[ 'tostring / concatstrings', %q{ "#{true}" }, ],
[ 'toregexp', %q{ /#{true}/ =~ "true" && $~ }, ],
[ 'intern', %q{ :"#{true}" }, ],
[ 'newarray', %q{ ["true"][0] }, ],
[ 'pushtoarraykwsplat', %q{ [**{x:'true'}][0][:x] }, ],
[ '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] }, ],
[ 'newhashfromarray', %q{ { a: true }[:a] }, ],
[ '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', %q{ !!defined?([[]]) }, ],
[ '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_nil_p', %q{ nil.nil? }, ],
[ 'opt_nil_p', %q{ !Object.nil? }, ],
[ 'opt_nil_p', %q{ Class.new{def nil?; true end}.new.nil? }, ],
[ 'opt_str_uminus', %q{ -'true' }, ],
[ 'opt_str_freeze', <<-'},', ], # {
class String
def freeze
true
end
end
'true'.freeze
},
[ 'opt_newarray_send', %q{ ![ ].hash.nil? }, ],
[ 'opt_newarray_send', %q{ [ ].max.nil? }, ],
[ 'opt_newarray_send', %q{ [1, x = 2, 3].max == 3 }, ],
[ 'opt_newarray_send', <<-'},', ], # {
class Array
def max
true
end
end
[1, x = 2, 3].max
},
[ 'opt_newarray_send', %q{ [ ].min.nil? }, ],
[ 'opt_newarray_send', %q{ [3, x = 2, 1].min == 1 }, ],
[ 'opt_newarray_send', <<-'},', ], # {
class Array
def min
true
end
end
[3, x = 2, 1].min
},
[ 'opt_newarray_send', %q{ v = 1.23; [v, v*2].pack("E*").unpack("E*") == [v, v*2] }, ],
[ 'opt_newarray_send', %q{ v = 4.56; b = +"x"; [v, v*2].pack("E*", buffer: b); b[1..].unpack("E*") == [v, v*2] }, ],
[ 'opt_newarray_send', <<-'},', ], # {
v = 7.89;
b = +"x";
class Array
alias _pack pack
def pack(s, buffer: nil, prefix: "y")
buffer ||= +"b"
buffer << prefix
_pack(s, buffer: buffer)
end
end
tests = []
ret = [v].pack("E*", prefix: "z")
tests << (ret[0..1] == "bz")
tests << (ret[2..].unpack("E*") == [v])
ret = [v].pack("E*")
tests << (ret[0..1] == "by")
tests << (ret[2..].unpack("E*") == [v])
[v, v*2, v*3].pack("E*", buffer: b)
tests << (b[0..1] == "xy")
tests << (b[2..].unpack("E*") == [v, v*2, v*3])
class Array
def pack(_fmt, buffer:) = buffer
end
b = nil
tests << [v].pack("E*", buffer: b).nil?
class Array
def pack(_fmt, **kw) = kw.empty?
end
tests << [v].pack("E*") == true
tests.all? or puts tests
},
[ '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{ Thread::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_not', %q{ ! false }, ],
[ 'opt_neq', <<-'},', ], # {
class X; def !; true; end; end
! X.new
},
[ 'opt_regexpmatch2', %q{ /true/ =~ 'true' && $~ }, ],
[ 'opt_regexpmatch2', <<-'},', ], # {
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/
},
]
# normal path
tests.compact.each do |(insn, expr, *a)|
if a.last.is_a?(Hash)
a = a.dup
kw = a.pop
assert_equal 'true', expr, insn, *a, **kw
else
assert_equal 'true', expr, insn, *a
end
end
# with trace
tests.compact.each {|(insn, expr, *a)|
progn = "set_trace_func(proc{})\n" + expr
if a.last.is_a?(Hash)
a = a.dup
kw = a.pop
assert_equal 'true', progn, 'trace_' + insn, *a, **kw
else
assert_equal 'true', progn, 'trace_' + insn, *a
end
}
assert_normal_exit("#{<<-"begin;"}\n#{<<-'end;'}")
begin;
RubyVM::InstructionSequence.compile("", debug_level: 5)
end;