[前][次][番号順一覧][スレッド一覧]

ruby-changes:45327

From: shyouhei <ko1@a...>
Date: Mon, 23 Jan 2017 11:47:25 +0900 (JST)
Subject: [ruby-changes:45327] shyouhei:r57399 (trunk): improve C0 coverage of insns.def from 65.9% to 96.1%

shyouhei	2017-01-23 11:47:16 +0900 (Mon, 23 Jan 2017)

  New Revision: 57399

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=57399

  Log:
    improve C0 coverage of insns.def from 65.9% to 96.1%
    
    While I was developing my private topic branch I found that the VM
    itself is not tested very much in `make test` tests.  Of course
    `make test-all` covers vast majority of the VM but running that task
    is not an immediately possible thing when we are touching the VM.  In
    order to boost development in a rapid cycle I decided to add some
    tests to the bootstraptest.  Here it is.
    
    * test_insns.rb: new test that covers insns.def.
    
    * runner.rb (#assert_equal): pass extra options to the target
      so that we can test frozen_string_literal: true situation.

  Added files:
    trunk/bootstraptest/test_insns.rb
  Modified files:
    trunk/bootstraptest/runner.rb
Index: bootstraptest/runner.rb
===================================================================
--- bootstraptest/runner.rb	(revision 57398)
+++ bootstraptest/runner.rb	(revision 57399)
@@ -267,17 +267,17 @@ def nacl? https://github.com/ruby/ruby/blob/trunk/bootstraptest/runner.rb#L267
   @ruby and File.basename(@ruby.split(/\s/).first)['sel_ldr']
 end
 
-def assert_check(testsrc, message = '', opt = '')
+def assert_check(testsrc, message = '', opt = '', **argh)
   show_progress(message) {
-    result = get_result_string(testsrc, opt)
+    result = get_result_string(testsrc, opt, **argh)
     check_coredump
     yield(result)
   }
 end
 
-def assert_equal(expected, testsrc, message = '')
+def assert_equal(expected, testsrc, message = '', opt = '', **argh)
   newtest
-  assert_check(testsrc, message) {|result|
+  assert_check(testsrc, message, opt, **argh) {|result|
     if expected == result
       nil
     else
@@ -419,18 +419,19 @@ def untabify(str) https://github.com/ruby/ruby/blob/trunk/bootstraptest/runner.rb#L419
   str.gsub(/^\t+/) {' ' * (8 * $&.size) }
 end
 
-def make_srcfile(src)
+def make_srcfile(src, frozen_string_literal: nil)
   filename = 'bootstraptest.tmp.rb'
   File.open(filename, 'w') {|f|
+    f.puts "#frozen_string_literal:true" if frozen_string_literal
     f.puts "GC.stress = true" if $stress
     f.puts "print(begin; #{src}; end)"
   }
   filename
 end
 
-def get_result_string(src, opt = '')
+def get_result_string(src, opt = '', **argh)
   if @ruby
-    filename = make_srcfile(src)
+    filename = make_srcfile(src, **argh)
     begin
       `#{@ruby} -W0 #{opt} #{filename}`
     ensure
Index: bootstraptest/test_insns.rb
===================================================================
--- bootstraptest/test_insns.rb	(revision 0)
+++ bootstraptest/test_insns.rb	(revision 57399)
@@ -0,0 +1,391 @@ https://github.com/ruby/ruby/blob/trunk/bootstraptest/test_insns.rb#L1
+# 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
+  bits = 8 * RbConfig::SIZEOF['long']
+  $LONG_MAX = (1 << (bits - 1)) - 1
+  $LONG_MIN = -1 * $LONG_MAX - 1
+  $FIXNUM_MAX = $LONG_MAX >> 1
+  $FIXNUM_MIN = $LONG_MIN >> 1
+end
+
+fsl   = { frozen_string_literal: true } # used later
+tests = [
+  # insn ,   expression to generate such insn
+  [ 'nop',   %q{ raise rescue true }, ],
+  [ 'trace', %q{ 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 }.() }.() }, ],
+
+  [ '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 == "x" }, ],
+
+  [ 'putspecialobject',         %q{ {//=>true}[//] }, ],
+  [ 'putiseq',                  %q{ -> { true }.() }, ],
+  [ 'putstring',                %q{ "true" }, ],
+  [ 'tostring / concatstrings', %q{ "#{true}" }, ],
+  [ 'freezestring',             %q{ "#{true}"}, fsl, ],
+  [ 'freezestring',             %q{ "#{true}"}, '-d', fsl, ],
+  [ 'torexp',                   %q{ /#{true}/ =~ "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 }, ],
+  [ '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 }, ],
+  [ '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_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 ||= assinment 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? $LONG_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? $LONG_MAX 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? $LONG_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/
+  },
+]
+
+tests.compact.each {|(insn, expr, *a)| assert_equal 'true', expr, insn, *a }

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]