Module: RubyVM::RJIT

Defined in:
lib/ruby_vm/rjit/branch_stub.rb,
lib/ruby_vm/rjit/invariants.rb,
lib/ruby_vm/rjit/entry_stub.rb,
lib/ruby_vm/rjit/code_block.rb,
lib/ruby_vm/rjit/jit_state.rb,
lib/ruby_vm/rjit/c_pointer.rb,
lib/ruby_vm/rjit/assembler.rb,
lib/ruby_vm/rjit/compiler.rb,
lib/ruby_vm/rjit/context.rb,
lib/ruby_vm/rjit/c_type.rb,
lib/ruby_vm/rjit/stats.rb,
lib/ruby_vm/rjit/hooks.rb,
lib/ruby_vm/rjit/type.rb

Defined Under Namespace

Modules: CPointer, CType, Hooks, OperandMatcher, TypeDiff Classes: Assembler, BranchStub, BranchTarget, BytePtr, CodeBlock, Compiler, Context, DwordPtr, EntryStub, Invariants, JITState

Constant Summary collapse

Next0 =

Branch shapes

:Next0
Next1 =

target0 is a fallthrough

:Next1
Default =

target1 is a fallthrough

:Default
QwordPtr =

64-bit memory access

Array
C_ARGS =

SystemV x64 calling convention

[:rdi, :rsi, :rdx, :rcx, :r8, :r9]
C_RET =
:rax
KeepCompiling =

Compilation status

:KeepCompiling
CantCompile =
:CantCompile
EndBlock =
:EndBlock
Qtrue =

Ruby constants

Fiddle::Qtrue
Qfalse =
Fiddle::Qfalse
Qnil =
Fiddle::Qnil
Qundef =
Fiddle::Qundef
EC =

Callee-saved registers TODO: support using r12/r13 here

:r14
CFP =
:r15
SP =
:rbx
GC_REFS =

Mark objects in this Array during GC

[]
MAX_VERSIONS =

Maximum number of versions per block 1 means always create generic versions

4
MAX_TEMP_TYPES =

Maximum number of temp value types we keep track of

8
MAX_LOCAL_TYPES =

Maximum number of local variable types we keep track of

8
SelfOpnd =

Operand to a YARV bytecode instruction

:SelfOpnd
StackOpnd =

The value is self

Data.define(:index)
MapToStack =

Potential mapping of a value on the temporary stack to self, a local variable, or constant so that we can track its type

:MapToStack
MapToSelf =

Normal stack value

:MapToSelf
MapToLocal =

Temp maps to the self operand

Data.define(:local_index)
Type =

Represent the type of a value (local/stack/self) in RJIT

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

Class Method Summary collapse

Class Method Details

.runtime_statsObject

Return a Hash for RJIT statistics. --rjit-stats makes more information available.



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/ruby_vm/rjit/stats.rb', line 4

def self.runtime_stats
  stats = {}

  # Insn exits
  INSNS.each_value do |insn|
    exits = C.rjit_insn_exits[insn.bin]
    if exits > 0
      stats[:"exit_#{insn.name}"] = exits
    end
  end

  # Runtime stats
  C.rb_rjit_runtime_counters.members.each do |member|
    stats[member] = C.rb_rjit_counters.public_send(member)
  end
  stats[:vm_insns_count] = C.rb_vm_insns_count

  # Other stats are calculated here
  stats[:side_exit_count] = stats.select { |name, _count| name.start_with?('exit_') }.sum(&:last)
  if stats[:vm_insns_count] > 0
    retired_in_rjit = stats[:rjit_insns_count] - stats[:side_exit_count]
    stats[:total_insns_count] = retired_in_rjit + stats[:vm_insns_count]
    stats[:ratio_in_rjit] = 100.0 * retired_in_rjit / stats[:total_insns_count]
  else
    stats.delete(:vm_insns_count)
  end

  stats
end