Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions gc/default/default.c
Original file line number Diff line number Diff line change
Expand Up @@ -1046,8 +1046,18 @@ total_final_slots_count(rb_objspace_t *objspace)
#define is_full_marking(objspace) ((objspace)->flags.during_minor_gc == FALSE)
#define is_incremental_marking(objspace) ((objspace)->flags.during_incremental_marking != FALSE)
#define will_be_incremental_marking(objspace) ((objspace)->rgengc.need_major_gc != GPR_FLAG_NONE)
#define GC_INCREMENTAL_SWEEP_SLOT_COUNT 2048
#define GC_INCREMENTAL_SWEEP_POOL_SLOT_COUNT 1024
/*
* Byte budget for incremental sweep steps. Each step sweeps at most
* this many bytes worth of slots before yielding. The effective slot
* count per step is GC_INCREMENTAL_SWEEP_BYTES / heap->slot_size,
* so larger slot pools (which are less heavily used) naturally get
* fewer slots swept per step.
*
* Baseline: 2048 slots * RVALUE_SLOT_SIZE = 2048 * 40 = 81920 bytes,
* preserving the historical behavior for the smallest heap.
*/
#define GC_INCREMENTAL_SWEEP_BYTES (2048 * RVALUE_SLOT_SIZE)
#define GC_INCREMENTAL_SWEEP_POOL_BYTES (1024 * RVALUE_SLOT_SIZE)
#define is_lazy_sweeping(objspace) (GC_ENABLE_LAZY_SWEEP && has_sweeping_pages(objspace))
/* In lazy sweeping or the previous incremental marking finished and did not yield a free page. */
#define needs_continue_sweeping(objspace, heap) \
Expand Down Expand Up @@ -3877,6 +3887,8 @@ gc_sweep_step(rb_objspace_t *objspace, rb_heap_t *heap)
struct heap_page *sweep_page = heap->sweeping_page;
int swept_slots = 0;
int pooled_slots = 0;
int sweep_budget = GC_INCREMENTAL_SWEEP_BYTES / heap->slot_size;
int pool_budget = GC_INCREMENTAL_SWEEP_POOL_BYTES / heap->slot_size;

if (sweep_page == NULL) return FALSE;

Expand Down Expand Up @@ -3922,14 +3934,14 @@ gc_sweep_step(rb_objspace_t *objspace, rb_heap_t *heap)
heap->freed_slots += ctx.freed_slots;
heap->empty_slots += ctx.empty_slots;

if (pooled_slots < GC_INCREMENTAL_SWEEP_POOL_SLOT_COUNT) {
if (pooled_slots < pool_budget) {
heap_add_poolpage(objspace, heap, sweep_page);
pooled_slots += free_slots;
}
else {
heap_add_freepage(heap, sweep_page);
swept_slots += free_slots;
if (swept_slots > GC_INCREMENTAL_SWEEP_SLOT_COUNT) {
if (swept_slots > sweep_budget) {
break;
}
}
Expand Down
11 changes: 0 additions & 11 deletions spec/mspec/tool/sync/sync-rubyspec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -207,16 +207,6 @@ def test_new_specs
end
end

def verify_commits(impl)
puts
Dir.chdir(SOURCE_REPO) do
puts "Manually check commit messages:"
print "Press enter >"
STDIN.gets
system "git", "log", "master..."
end
end

def fast_forward_master(impl)
Dir.chdir(SOURCE_REPO) do
sh "git", "checkout", "master"
Expand All @@ -243,7 +233,6 @@ def main(impls)
rebase_commits(impl)
if new_commits?(impl)
test_new_specs
verify_commits(impl)
fast_forward_master(impl)
check_ci
else
Expand Down
14 changes: 14 additions & 0 deletions spec/ruby/core/encoding/compatible_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,11 @@
[Encoding, "\x82\xa0".dup.force_encoding("shift_jis"), Encoding::Shift_JIS],
].should be_computed_by(:compatible?, /abc/)
end

it "returns the Regexp's Encoding if the String is ASCII only and the Regexp is not" do
r = Regexp.new("\xa4\xa2".dup.force_encoding("euc-jp"))
Encoding.compatible?("hello".dup.force_encoding("utf-8"), r).should == Encoding::EUC_JP
end
end

describe "Encoding.compatible? String, Symbol" do
Expand Down Expand Up @@ -619,6 +624,15 @@
Encoding.compatible?(/abc/, str).should == Encoding::US_ASCII
end

it "returns the String's Encoding when the String is ASCII only with a different encoding" do
r = Regexp.new("\xa4\xa2".dup.force_encoding("euc-jp"))
Encoding.compatible?(r, "hello".dup.force_encoding("utf-8")).should == Encoding::UTF_8
end

it "returns the Regexp's Encoding if the String has the same non-ASCII encoding" do
r = Regexp.new("\xa4\xa2".dup.force_encoding("euc-jp"))
Encoding.compatible?(r, "hello".dup.force_encoding("euc-jp")).should == Encoding::EUC_JP
end
end

describe "Encoding.compatible? Regexp, Regexp" do
Expand Down
8 changes: 8 additions & 0 deletions spec/ruby/core/integer/comparison_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@
end
end

describe "with a Float" do
it "does not lose precision for values that don't fit in a double" do
(bignum_value(1) <=> bignum_value.to_f).should == 1
(bignum_value <=> bignum_value.to_f).should == 0
((bignum_value - 1) <=> bignum_value.to_f).should == -1
end
end

# The tests below are taken from matz's revision 23730 for Ruby trunk
it "returns 1 when self is Infinity and other is a Bignum" do
(infinity_value <=> Float::MAX.to_i*2).should == 1
Expand Down
25 changes: 25 additions & 0 deletions spec/ruby/core/integer/eql_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require_relative '../../spec_helper'

describe "Integer#eql?" do
context "bignum" do
it "returns true for the same value" do
bignum_value.eql?(bignum_value).should == true
end

it "returns false for a different Integer value" do
bignum_value.eql?(bignum_value(1)).should == false
end

it "returns false for a Float with the same numeric value" do
bignum_value.eql?(bignum_value.to_f).should == false
end

it "returns false for a Rational with the same numeric value" do
bignum_value.eql?(Rational(bignum_value)).should == false
end

it "returns false for a Fixnum-range Integer" do
bignum_value.eql?(42).should == false
end
end
end
10 changes: 10 additions & 0 deletions spec/ruby/core/integer/fixtures/classes.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
module IntegerSpecs
class CoerceError < StandardError
end

class CoercibleNumeric
def initialize(v) @v = v end
def coerce(other) [self.class.new(other), self] end
def >(other) @v.to_i > other.to_i end
def >=(other) @v.to_i >= other.to_i end
def <(other) @v.to_i < other.to_i end
def <=(other) @v.to_i <= other.to_i end
def to_i() @v.to_i end
end
end
5 changes: 5 additions & 0 deletions spec/ruby/core/integer/gt_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,10 @@
-> { @bignum > "4" }.should raise_error(ArgumentError)
-> { @bignum > mock('str') }.should raise_error(ArgumentError)
end

it "dispatches the correct operator after coercion" do
(bignum_value > IntegerSpecs::CoercibleNumeric.new(1)).should == true
(bignum_value > IntegerSpecs::CoercibleNumeric.new(bignum_value * 2)).should == false
end
end
end
5 changes: 5 additions & 0 deletions spec/ruby/core/integer/gte_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,10 @@
-> { @bignum >= "4" }.should raise_error(ArgumentError)
-> { @bignum >= mock('str') }.should raise_error(ArgumentError)
end

it "dispatches the correct operator after coercion" do
(bignum_value >= IntegerSpecs::CoercibleNumeric.new(1)).should == true
(bignum_value >= IntegerSpecs::CoercibleNumeric.new(bignum_value * 2)).should == false
end
end
end
5 changes: 5 additions & 0 deletions spec/ruby/core/integer/lt_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,10 @@
-> { @bignum < "4" }.should raise_error(ArgumentError)
-> { @bignum < mock('str') }.should raise_error(ArgumentError)
end

it "dispatches the correct operator after coercion" do
(bignum_value < IntegerSpecs::CoercibleNumeric.new(bignum_value * 2)).should == true
(bignum_value < IntegerSpecs::CoercibleNumeric.new(1)).should == false
end
end
end
5 changes: 5 additions & 0 deletions spec/ruby/core/integer/lte_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,10 @@
-> { @bignum <= "4" }.should raise_error(ArgumentError)
-> { @bignum <= mock('str') }.should raise_error(ArgumentError)
end

it "dispatches the correct operator after coercion" do
(bignum_value <= IntegerSpecs::CoercibleNumeric.new(bignum_value * 2)).should == true
(bignum_value <= IntegerSpecs::CoercibleNumeric.new(1)).should == false
end
end
end
5 changes: 5 additions & 0 deletions spec/ruby/core/integer/shared/equal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,10 @@
@bignum.send(@method, obj).should == true
@bignum.send(@method, obj).should == false
end

it "does not lose precision when comparing with a Float" do
(bignum_value(1).send(@method, bignum_value.to_f)).should == false
(bignum_value.send(@method, bignum_value.to_f)).should == true
end
end
end
19 changes: 19 additions & 0 deletions spec/ruby/core/kernel/fixtures/classes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,25 @@ class B < A
alias aliased_pub_method pub_method
end

class BasicA < BasicObject
define_method(:respond_to?, ::Kernel.instance_method(:respond_to?))

def pub_method; :public_method; end

def undefed_method; :undefed_method; end
undef_method :undefed_method

protected
def protected_method; :protected_method; end

private
def private_method; :private_method; end
end

class MissingA < A
undef :respond_to_missing?
end

class VisibilityChange
class << self
private :new
Expand Down
27 changes: 27 additions & 0 deletions spec/ruby/core/kernel/respond_to_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,31 @@ class KernelSpecs::Foo; def bar; 'done'; end; end
KernelSpecs::Foo.new.respond_to?(:bar).should == true
KernelSpecs::Foo.new.respond_to?(:invalid_and_silly_method_name).should == false
end

context "if object does not have #respond_to_missing?" do
it "returns true if object responds to the given public method" do
KernelSpecs::BasicA.new.respond_to?(:pub_method).should == true
KernelSpecs::MissingA.new.respond_to?(:pub_method).should == true
end

it "returns false if object responds to the given protected method" do
KernelSpecs::BasicA.new.respond_to?(:protected_method).should == false
KernelSpecs::MissingA.new.respond_to?(:protected_method).should == false
end

it "returns false if object responds to the given private method" do
KernelSpecs::BasicA.new.respond_to?(:private_method).should == false
KernelSpecs::MissingA.new.respond_to?(:private_method).should == false
end

it "returns false if the given method was undefined" do
KernelSpecs::BasicA.new.respond_to?(:undefed_method).should == false
KernelSpecs::MissingA.new.respond_to?(:undefed_method).should == false
end

it "returns false if the given method never existed" do
KernelSpecs::BasicA.new.respond_to?(:invalid_and_silly_method_name).should == false
KernelSpecs::MissingA.new.respond_to?(:invalid_and_silly_method_name).should == false
end
end
end
15 changes: 15 additions & 0 deletions spec/ruby/core/matchdata/deconstruct_keys_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,19 @@
m = /(?<f>foo)(?<b>bar)/.match("foobar")
m.deconstruct_keys([:f, :b, :c]).should == {}
end

it "includes non-participating captures as nil for nil argument" do
m = "hello".match(/(?<a>hello)(?<b>world)?/)
m.deconstruct_keys(nil).should == { a: "hello", b: nil }
end

it "includes non-participating captures as nil for explicit keys" do
m = "hello".match(/(?<a>hello)(?<b>world)?/)
m.deconstruct_keys([:a, :b]).should == { a: "hello", b: nil }
end

it "does not stop iterating at a non-participating capture" do
m = "hello!".match(/(?<a>hello)(?<b>world)?(?<c>!)/)
m.deconstruct_keys([:b, :c, :a]).should == { b: nil, c: "!", a: "hello" }
end
end
44 changes: 42 additions & 2 deletions spec/ruby/core/process/spawn_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -694,13 +694,53 @@ def child_pids(pid)
end

it "raises an Errno::ENOENT if the command does not exist" do
-> { Process.spawn "nonesuch" }.should raise_error(Errno::ENOENT)
-> { Process.spawn "nonesuch" }.should raise_error(Errno::ENOENT, "No such file or directory - nonesuch")
end

it "sets $? to exit status 127 when the command does not exist" do
Process.spawn("nonesuch") rescue nil
$?.exitstatus.should == 127
end

it "raises an Errno::ENOENT if the file does not exist" do
-> { Process.spawn "./nonesuch" }.should raise_error(Errno::ENOENT, "No such file or directory - ./nonesuch")
end

it "sets $? to exit status 127 when the file does not exist" do
Process.spawn("./nonesuch") rescue nil
$?.exitstatus.should == 127
end

platform_is_not :windows do
it "raises an Errno::EACCES when the path is a directory" do
-> { Process.spawn "./" }.should raise_error(Errno::EACCES, "Permission denied - ./")
end
end

unless File.executable?(__FILE__) # Some FS (e.g. vboxfs) locate all files executable
platform_is_not :windows do
it "raises an Errno::EACCES when the file does not have execute permissions" do
-> { Process.spawn __FILE__ }.should raise_error(Errno::EACCES)
-> { Process.spawn __FILE__ }.should raise_error(Errno::EACCES, "Permission denied - #{__FILE__}")
end

it "sets $? to exit status 127 when the file does not have execute permissions" do
Process.spawn(__FILE__) rescue nil
$?.exitstatus.should == 127
end

it "raises an Errno::ENOENT when a non-executable file is found in PATH" do
dir = tmp("spawn_path_non_executable_dir")
mkdir_p dir
begin
exe = 'process-spawn-non-executable-in-path'
File.write("#{dir}/#{exe}", "#!/bin/sh\necho hi")
File.chmod(0644, "#{dir}/#{exe}")
env = { "PATH" => "#{dir}#{File::PATH_SEPARATOR}#{ENV['PATH']}" }
-> { Process.spawn(env, exe) }.should raise_error(Errno::ENOENT, "No such file or directory - #{exe}")
$?.exitstatus.should == 127
ensure
rm_r dir
end
end
end

Expand Down
Loading