mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			440 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			440 lines
		
	
	
	
		
			13 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] }, ],
 | |
|   [ 'newarraykwsplat', %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_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{ 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;
 | 
