Skip to content

Commit

Permalink
Merge pull request #477 from ybiquitous/add-object-space
Browse files Browse the repository at this point in the history
Add built-in ObjectSpace definition
  • Loading branch information
soutaro authored Nov 30, 2020
2 parents 44673ba + a828d37 commit fccfab9
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 0 deletions.
98 changes: 98 additions & 0 deletions core/object_space.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# The ObjectSpace module contains a number of routines that interact with the
# garbage collection facility and allow you to traverse all living objects with
# an iterator.
#
# ObjectSpace also provides support for object finalizers, procs that will be
# called when a specific object is about to be destroyed by garbage collection.
#
# require 'objspace'
#
# a = "A"
# b = "B"
#
# ObjectSpace.define_finalizer(a, proc {|id| puts "Finalizer one on #{id}" })
# ObjectSpace.define_finalizer(b, proc {|id| puts "Finalizer two on #{id}" })
#
# *produces:*
#
# Finalizer two on 537763470
# Finalizer one on 537763480
module ObjectSpace
def self._id2ref: (Integer id) -> untyped

# Counts all objects grouped by type.
#
# It returns a hash, such as:
# {
# :TOTAL=>10000,
# :FREE=>3011,
# :T_OBJECT=>6,
# :T_CLASS=>404,
# # ...
# }
#
# The contents of the returned hash are implementation specific. It may be
# changed in future.
#
# The keys starting with `:T_` means live objects. For example, `:T_ARRAY` is
# the number of arrays. `:FREE` means object slots which is not used now.
# `:TOTAL` means sum of above.
#
# If the optional argument `result_hash` is given, it is overwritten and
# returned. This is intended to avoid probe effect.
#
# h = {}
# ObjectSpace.count_objects(h)
# puts h
# # => { :TOTAL=>10000, :T_CLASS=>158280, :T_MODULE=>20672, :T_STRING=>527249 }
#
# This method is only expected to work on C Ruby.
#
def self.count_objects: (?Hash[Symbol, Integer] result_hash) -> Hash[Symbol, Integer]

# Adds *aProc* as a finalizer, to be called after *obj* was destroyed. The
# object ID of the *obj* will be passed as an argument to *aProc*. If *aProc* is
# a lambda or method, make sure it can be called with a single argument.
#
def self.define_finalizer: (untyped obj, ^(Integer id) -> void aProc) -> [ Integer, Proc ]
| (untyped obj) { (Integer id) -> void } -> [ Integer, Proc ]

# Calls the block once for each living, nonimmediate object in this Ruby
# process. If *module* is specified, calls the block for only those classes or
# modules that match (or are a subclass of) *module*. Returns the number of
# objects found. Immediate objects (`Fixnum`s, `Symbol`s `true`, `false`, and
# `nil`) are never returned. In the example below, #each_object returns both the
# numbers we defined and several constants defined in the Math module.
#
# If no block is given, an enumerator is returned instead.
#
# a = 102.7
# b = 95 # Won't be returned
# c = 12345678987654321
# count = ObjectSpace.each_object(Numeric) {|x| p x }
# puts "Total count: #{count}"
#
# *produces:*
#
# 12345678987654321
# 102.7
# 2.71828182845905
# 3.14159265358979
# 2.22044604925031e-16
# 1.7976931348623157e+308
# 2.2250738585072e-308
# Total count: 7
#
def self.each_object: (?Module `module`) -> Enumerator[untyped, Integer]
| (?Module `module`) { (untyped obj) -> void } -> Integer

def self.garbage_collect: (?full_mark: bool, ?immediate_mark: bool, ?immediate_sweep: bool) -> void

# Removes all finalizers for *obj*.
#
def self.undefine_finalizer: [X] (X obj) -> X

private

def garbage_collect: (?full_mark: bool, ?immediate_mark: bool, ?immediate_sweep: bool) -> void
end
58 changes: 58 additions & 0 deletions test/stdlib/ObjectSpace_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
require_relative "test_helper"

class ObjectSpaceTest < Minitest::Test
include TypeAssertions

testing "singleton(::ObjectSpace)"

def test__id2ref
assert_send_type "(Integer) -> top",
ObjectSpace, :_id2ref, 198
end

def test_count_objects
assert_send_type "() -> Hash[Symbol, Integer]",
ObjectSpace, :count_objects
assert_send_type "(Hash[Symbol, Integer]) -> Hash[Symbol, Integer]",
ObjectSpace, :count_objects, {}
assert_send_type "(Hash[Symbol, Integer]) -> Hash[Symbol, Integer]",
ObjectSpace, :count_objects, { TOTAL: 0 }
end

def test_define_finalizer
assert_send_type "(top, ^(Integer) -> void) -> [Integer, Proc]",
ObjectSpace, :define_finalizer, "abc", ->(id) { "id: #{id}" }
assert_send_type "(top) { (Integer) -> void } -> [Integer, Proc]",
ObjectSpace, :define_finalizer, "abc" do |id| "id: #{id}" end
end

def test_each_object
klass = Class.new
klass.new

# NOTE: Commented out because they're too slow.
# assert_send_type "() -> Enumerator[top, Integer]",
# ObjectSpace, :each_object
# assert_send_type "() { (top) -> void } -> Integer",
# ObjectSpace, :each_object do |obj| obj.to_s end

assert_send_type "(Module) -> Enumerator[top, Integer]",
ObjectSpace, :each_object, klass
assert_send_type "(Module) { (top) -> void } -> Integer",
ObjectSpace, :each_object, klass do |obj| obj.to_s end
end

def test_garbage_collect
assert_send_type "() -> void",
ObjectSpace, :garbage_collect
assert_send_type "(full_mark: bool, immediate_mark: bool, immediate_sweep: bool) -> void",
ObjectSpace, :garbage_collect, full_mark: false, immediate_mark: false, immediate_sweep: false
end

def test_undefine_finalizer
assert_send_type "(String) -> String",
ObjectSpace, :undefine_finalizer, "abc"
assert_send_type "(Array) -> Array",
ObjectSpace, :undefine_finalizer, []
end
end

0 comments on commit fccfab9

Please # to comment.