Your IP : 3.141.25.125
module RubyVM::RJIT
# Represent the type of a value (local/stack/self) in RJIT
Type = Data.define(:type) do
# Check if the type is an immediate
def imm?
case self
in Type::UnknownImm then true
in Type::Nil then true
in Type::True then true
in Type::False then true
in Type::Fixnum then true
in Type::Flonum then true
in Type::ImmSymbol then true
else false
end
end
# Returns true when the type is not specific.
def unknown?
case self
in Type::Unknown | Type::UnknownImm | Type::UnknownHeap then true
else false
end
end
# Returns true when we know the VALUE is a specific handle type,
# such as a static symbol ([Type::ImmSymbol], i.e. true from RB_STATIC_SYM_P()).
# Opposite of [Self::is_unknown].
def specific?
!self.unknown?
end
# Check if the type is a heap object
def heap?
case self
in Type::UnknownHeap then true
in Type::TArray then true
in Type::Hash then true
in Type::HeapSymbol then true
in Type::TString then true
in Type::CString then true
in Type::BlockParamProxy then true
else false
end
end
# Check if it's a T_ARRAY object
def array?
case self
in Type::TArray then true
else false
end
end
# Check if it's a T_STRING object (both TString and CString are T_STRING)
def string?
case self
in Type::TString then true
in Type::CString then true
else false
end
end
# Returns the class if it is known, otherwise nil
def known_class
case self
in Type::Nil then C.rb_cNilClass
in Type::True then C.rb_cTrueClass
in Type::False then C.rb_cFalseClass
in Type::Fixnum then C.rb_cInteger
in Type::Flonum then C.rb_cFloat
in Type::ImmSymbol | Type::HeapSymbol then C.rb_cSymbol
in Type::CString then C.rb_cString
else nil
end
end
# Returns a boolean representing whether the value is truthy if known, otherwise nil
def known_truthy
case self
in Type::Nil then false
in Type::False then false
in Type::UnknownHeap then false
in Type::Unknown | Type::UnknownImm then nil
else true
end
end
# Returns a boolean representing whether the value is equal to nil if known, otherwise nil
def known_nil
case [self, self.known_truthy]
in Type::Nil, _ then true
in Type::False, _ then false # Qfalse is not nil
in _, true then false # if truthy, can't be nil
in _, _ then nil # otherwise unknown
end
end
def diff(dst)
# Perfect match, difference is zero
if self == dst
return TypeDiff::Compatible[0]
end
# Any type can flow into an unknown type
if dst == Type::Unknown
return TypeDiff::Compatible[1]
end
# A CString is also a TString.
if self == Type::CString && dst == Type::TString
return TypeDiff::Compatible[1]
end
# Specific heap type into unknown heap type is imperfect but valid
if self.heap? && dst == Type::UnknownHeap
return TypeDiff::Compatible[1]
end
# Specific immediate type into unknown immediate type is imperfect but valid
if self.imm? && dst == Type::UnknownImm
return TypeDiff::Compatible[1]
end
# Incompatible types
return TypeDiff::Incompatible
end
def upgrade(new_type)
assert(new_type.diff(self) != TypeDiff::Incompatible)
new_type
end
private
def assert(cond)
unless cond
raise "'#{cond.inspect}' was not true"
end
end
end
# This returns an appropriate Type based on a known value
class << Type
def from(val)
if C::SPECIAL_CONST_P(val)
if fixnum?(val)
Type::Fixnum
elsif val.nil?
Type::Nil
elsif val == true
Type::True
elsif val == false
Type::False
elsif static_symbol?(val)
Type::ImmSymbol
elsif flonum?(val)
Type::Flonum
else
raise "Illegal value: #{val.inspect}"
end
else
val_class = C.to_value(C.rb_class_of(val))
if val_class == C.rb_cString && C.rb_obj_frozen_p(val)
return Type::CString
end
if C.to_value(val) == C.rb_block_param_proxy
return Type::BlockParamProxy
end
case C::BUILTIN_TYPE(val)
in C::RUBY_T_ARRAY
Type::TArray
in C::RUBY_T_HASH
Type::Hash
in C::RUBY_T_STRING
Type::TString
else
Type::UnknownHeap
end
end
end
private
def fixnum?(obj)
(C.to_value(obj) & C::RUBY_FIXNUM_FLAG) == C::RUBY_FIXNUM_FLAG
end
def flonum?(obj)
(C.to_value(obj) & C::RUBY_FLONUM_MASK) == C::RUBY_FLONUM_FLAG
end
def static_symbol?(obj)
(C.to_value(obj) & 0xff) == C::RUBY_SYMBOL_FLAG
end
end
# List of types
Type::Unknown = Type[:Unknown]
Type::UnknownImm = Type[:UnknownImm]
Type::UnknownHeap = Type[:UnknownHeap]
Type::Nil = Type[:Nil]
Type::True = Type[:True]
Type::False = Type[:False]
Type::Fixnum = Type[:Fixnum]
Type::Flonum = Type[:Flonum]
Type::Hash = Type[:Hash]
Type::ImmSymbol = Type[:ImmSymbol]
Type::HeapSymbol = Type[:HeapSymbol]
Type::TString = Type[:TString] # An object with the T_STRING flag set, possibly an rb_cString
Type::CString = Type[:CString] # An un-subclassed string of type rb_cString (can have instance vars in some cases)
Type::TArray = Type[:TArray] # An object with the T_ARRAY flag set, possibly an rb_cArray
Type::BlockParamProxy = Type[:BlockParamProxy] # A special sentinel value indicating the block parameter should be read from
module TypeDiff
Compatible = Data.define(:diversion) # The smaller, the more compatible.
Incompatible = :Incompatible
end
end