summaryrefslogtreecommitdiff
path: root/tool/ruby_vm/models
diff options
context:
space:
mode:
Diffstat (limited to 'tool/ruby_vm/models')
-rw-r--r--tool/ruby_vm/models/attribute.rb20
-rw-r--r--[-rwxr-xr-x]tool/ruby_vm/models/bare_instruction.rb (renamed from tool/ruby_vm/models/bare_instructions.rb)53
-rw-r--r--tool/ruby_vm/models/c_expr.rb7
-rw-r--r--tool/ruby_vm/models/instructions.rb19
-rw-r--r--tool/ruby_vm/models/instructions_unification.rb (renamed from tool/ruby_vm/models/instructions_unifications.rb)9
-rw-r--r--tool/ruby_vm/models/operands_unification.rb (renamed from tool/ruby_vm/models/operands_unifications.rb)19
-rw-r--r--tool/ruby_vm/models/trace_instruction.rb (renamed from tool/ruby_vm/models/trace_instructions.rb)13
-rw-r--r--tool/ruby_vm/models/typemap.rb8
-rw-r--r--tool/ruby_vm/models/zjit_instruction.rb56
9 files changed, 143 insertions, 61 deletions
diff --git a/tool/ruby_vm/models/attribute.rb b/tool/ruby_vm/models/attribute.rb
index cc16a5f898..177b701b92 100644
--- a/tool/ruby_vm/models/attribute.rb
+++ b/tool/ruby_vm/models/attribute.rb
@@ -1,4 +1,3 @@
-#! /your/favourite/path/to/ruby
# -*- Ruby -*-
# -*- frozen_string_literal: true; -*-
# -*- warn_indent: true; -*-
@@ -21,6 +20,13 @@ class RubyVM::Attribute
@key = opts[:name]
@expr = RubyVM::CExpr.new location: opts[:location], expr: opts[:expr]
@type = opts[:type]
+ @ope_decls = @insn.operands.map do |operand|
+ decl = operand[:decl]
+ if @key == 'comptime_sp_inc' && operand[:type] == 'CALL_DATA'
+ decl = decl.gsub('CALL_DATA', 'CALL_INFO').gsub('cd', 'ci')
+ end
+ decl
+ end
end
def name
@@ -32,22 +38,20 @@ class RubyVM::Attribute
end
def declaration
- opes = @insn.opes
- if opes.empty?
+ if @ope_decls.empty?
argv = "void"
else
- argv = opes.map {|o| o[:decl] }.join(', ')
+ argv = @ope_decls.join(', ')
end
sprintf '%s %s(%s)', @type, name, argv
end
def definition
- opes = @insn.opes
- if opes.empty?
+ if @ope_decls.empty?
argv = "void"
else
- argv = opes.map {|o| "MAYBE_UNUSED(#{o[:decl]})" }.join(",\n ")
- argv = "\n #{argv}\n" if opes.size > 1
+ argv = @ope_decls.map {|decl| "MAYBE_UNUSED(#{decl})" }.join(",\n ")
+ argv = "\n #{argv}\n" if @ope_decls.size > 1
end
sprintf "%s\n%s(%s)", @type, name, argv
end
diff --git a/tool/ruby_vm/models/bare_instructions.rb b/tool/ruby_vm/models/bare_instruction.rb
index e0fac5ff91..f87dd74179 100755..100644
--- a/tool/ruby_vm/models/bare_instructions.rb
+++ b/tool/ruby_vm/models/bare_instruction.rb
@@ -1,4 +1,3 @@
-#! /your/favourite/path/to/ruby
# -*- Ruby -*-
# -*- frozen_string_literal: true; -*-
# -*- warn_indent: true; -*-
@@ -15,8 +14,8 @@ require_relative 'c_expr'
require_relative 'typemap'
require_relative 'attribute'
-class RubyVM::BareInstructions
- attr_reader :template, :name, :opes, :pops, :rets, :decls, :expr
+class RubyVM::BareInstruction
+ attr_reader :template, :name, :operands, :pops, :rets, :decls, :expr
def initialize opts = {}
@template = opts[:template]
@@ -24,7 +23,7 @@ class RubyVM::BareInstructions
@loc = opts[:location]
@sig = opts[:signature]
@expr = RubyVM::CExpr.new opts[:expr]
- @opes = typesplit @sig[:ope]
+ @operands = typesplit @sig[:ope]
@pops = typesplit @sig[:pop].reject {|i| i == '...' }
@rets = typesplit @sig[:ret].reject {|i| i == '...' }
@attrs = opts[:attributes].map {|i|
@@ -33,6 +32,7 @@ class RubyVM::BareInstructions
h[a.key] = a
}
@attrs_orig = @attrs.dup
+ check_attribute_consistency
predefine_attributes
end
@@ -50,7 +50,7 @@ class RubyVM::BareInstructions
def call_attribute name
return sprintf 'attr_%s_%s(%s)', name, @name, \
- @opes.map {|i| i[:name] }.compact.join(', ')
+ @operands.map {|i| i[:name] }.compact.join(', ')
end
def has_attribute? k
@@ -64,7 +64,7 @@ class RubyVM::BareInstructions
end
def width
- return 1 + opes.size
+ return 1 + operands.size
end
def declarations
@@ -97,7 +97,7 @@ class RubyVM::BareInstructions
end
def operands_info
- opes.map {|o|
+ operands.map {|o|
c, _ = RubyVM::Typemap.fetch o[:type]
next c
}.join
@@ -107,10 +107,6 @@ class RubyVM::BareInstructions
/\b(false|0)\b/ !~ @attrs.fetch('handles_sp').expr.expr
end
- def always_leaf?
- @attrs.fetch('leaf').expr.expr == 'true;'
- end
-
def handle_canary stmt
# Stack canary is basically a good thing that we want to add, however:
#
@@ -132,15 +128,39 @@ class RubyVM::BareInstructions
end
def has_ope? var
- return @opes.any? {|i| i[:name] == var[:name] }
+ return @operands.any? {|i| i[:name] == var[:name] }
end
def has_pop? var
return @pops.any? {|i| i[:name] == var[:name] }
end
+ def use_call_data?
+ @use_call_data ||=
+ @variables.find { |_, var_info| var_info[:type] == 'CALL_DATA' }
+ end
+
+ def zjit_profile?
+ @attrs.fetch('zjit_profile').expr.expr != 'false;'
+ end
+
private
+ def check_attribute_consistency
+ if has_attribute?('sp_inc') \
+ && use_call_data? \
+ && !has_attribute?('comptime_sp_inc')
+ # As the call cache caches information that can only be obtained at
+ # runtime, we do not need it when compiling from AST to bytecode. This
+ # attribute defines an expression that computes the stack pointer
+ # increase based on just the call info to avoid reserving space for the
+ # call cache at compile time. In the expression, all call data operands
+ # are mapped to their call info counterpart. Additionally, all mentions
+ # of `cd` in the operand name are replaced with `ci`.
+ raise "Please define attribute `comptime_sp_inc` for `#{@name}`"
+ end
+ end
+
def generate_attribute t, k, v
@attrs[k] ||= RubyVM::Attribute.new \
insn: self, \
@@ -155,18 +175,19 @@ class RubyVM::BareInstructions
# Beware: order matters here because some attribute depends another.
generate_attribute 'const char*', 'name', "insn_name(#{bin})"
generate_attribute 'enum ruby_vminsn_type', 'bin', bin
- generate_attribute 'rb_num_t', 'open', opes.size
+ generate_attribute 'rb_num_t', 'open', operands.size
generate_attribute 'rb_num_t', 'popn', pops.size
generate_attribute 'rb_num_t', 'retn', rets.size
generate_attribute 'rb_num_t', 'width', width
generate_attribute 'rb_snum_t', 'sp_inc', rets.size - pops.size
generate_attribute 'bool', 'handles_sp', default_definition_of_handles_sp
generate_attribute 'bool', 'leaf', default_definition_of_leaf
+ generate_attribute 'bool', 'zjit_profile', false
end
def default_definition_of_handles_sp
# Insn with ISEQ should yield it; can handle sp.
- return opes.any? {|o| o[:type] == 'ISEQ' }
+ return operands.any? {|o| o[:type] == 'ISEQ' }
end
def default_definition_of_leaf
@@ -203,13 +224,13 @@ class RubyVM::BareInstructions
new h.merge(:template => h)
}
- def self.fetch name
+ def self.find(name)
@instances.find do |insn|
insn.name == name
end or raise IndexError, "instruction not found: #{name}"
end
- def self.to_a
+ def self.all
@instances
end
end
diff --git a/tool/ruby_vm/models/c_expr.rb b/tool/ruby_vm/models/c_expr.rb
index 073112f545..095ff4f1d9 100644
--- a/tool/ruby_vm/models/c_expr.rb
+++ b/tool/ruby_vm/models/c_expr.rb
@@ -1,4 +1,3 @@
-#! /your/favourite/path/to/ruby
# -*- Ruby -*-
# -*- frozen_string_literal: true; -*-
# -*- warn_indent: true; -*-
@@ -36,6 +35,10 @@ class RubyVM::CExpr
end
def inspect
- sprintf "#<%s:%d %s>", @__FILE__, @__LINE__, @expr
+ if @__LINE__
+ sprintf "#<%s:%d %s>", @__FILE__, @__LINE__, @expr
+ else
+ sprintf "#<%s %s>", @__FILE__, @expr
+ end
end
end
diff --git a/tool/ruby_vm/models/instructions.rb b/tool/ruby_vm/models/instructions.rb
index 1198c7a4a6..7be7064b14 100644
--- a/tool/ruby_vm/models/instructions.rb
+++ b/tool/ruby_vm/models/instructions.rb
@@ -1,4 +1,3 @@
-#! /your/favourite/path/to/ruby
# -*- Ruby -*-
# -*- frozen_string_literal: true; -*-
# -*- warn_indent: true; -*-
@@ -10,13 +9,15 @@
# conditions mentioned in the file COPYING are met. Consult the file for
# details.
-require_relative 'bare_instructions'
-require_relative 'operands_unifications'
-require_relative 'instructions_unifications'
+require_relative 'bare_instruction'
+require_relative 'operands_unification'
+require_relative 'instructions_unification'
+require_relative 'trace_instruction'
+require_relative 'zjit_instruction'
-RubyVM::Instructions = RubyVM::BareInstructions.to_a + \
- RubyVM::OperandsUnifications.to_a + \
- RubyVM::InstructionsUnifications.to_a
-
-require_relative 'trace_instructions'
+RubyVM::Instructions = RubyVM::BareInstruction.all +
+ RubyVM::OperandsUnification.all +
+ RubyVM::InstructionsUnification.all +
+ RubyVM::TraceInstruction.all +
+ RubyVM::ZJITInstruction.all
RubyVM::Instructions.freeze
diff --git a/tool/ruby_vm/models/instructions_unifications.rb b/tool/ruby_vm/models/instructions_unification.rb
index 214ba5fcc2..5c798e6d54 100644
--- a/tool/ruby_vm/models/instructions_unifications.rb
+++ b/tool/ruby_vm/models/instructions_unification.rb
@@ -1,4 +1,3 @@
-#! /your/favourite/path/to/ruby
# -*- Ruby -*-
# -*- frozen_string_literal: true; -*-
# -*- warn_indent: true; -*-
@@ -12,9 +11,9 @@
require_relative '../helpers/c_escape'
require_relative '../loaders/opt_insn_unif_def'
-require_relative 'bare_instructions'
+require_relative 'bare_instruction'
-class RubyVM::InstructionsUnifications
+class RubyVM::InstructionsUnification
include RubyVM::CEscape
attr_reader :name
@@ -23,7 +22,7 @@ class RubyVM::InstructionsUnifications
@location = opts[:location]
@name = namegen opts[:signature]
@series = opts[:signature].map do |i|
- RubyVM::BareInstructions.fetch i # Misshit is fatal
+ RubyVM::BareInstruction.find(i) # Misshit is fatal
end
end
@@ -37,7 +36,7 @@ class RubyVM::InstructionsUnifications
new h
end
- def self.to_a
+ def self.all
@instances
end
end
diff --git a/tool/ruby_vm/models/operands_unifications.rb b/tool/ruby_vm/models/operands_unification.rb
index ee4e3a695d..ce118648ca 100644
--- a/tool/ruby_vm/models/operands_unifications.rb
+++ b/tool/ruby_vm/models/operands_unification.rb
@@ -1,4 +1,3 @@
-#! /your/favourite/path/to/ruby
# -*- Ruby -*-
# -*- frozen_string_literal: true; -*-
# -*- warn_indent: true; -*-
@@ -12,16 +11,16 @@
require_relative '../helpers/c_escape'
require_relative '../loaders/opt_operand_def'
-require_relative 'bare_instructions'
+require_relative 'bare_instruction'
-class RubyVM::OperandsUnifications < RubyVM::BareInstructions
+class RubyVM::OperandsUnification < RubyVM::BareInstruction
include RubyVM::CEscape
attr_reader :preamble, :original, :spec
def initialize opts = {}
name = opts[:signature][0]
- @original = RubyVM::BareInstructions.fetch name
+ @original = RubyVM::BareInstruction.find(name)
template = @original.template
parts = compose opts[:location], opts[:signature], template[:signature]
json = template.dup
@@ -38,8 +37,8 @@ class RubyVM::OperandsUnifications < RubyVM::BareInstructions
end
def operand_shift_of var
- before = @original.opes.find_index var
- after = @opes.find_index var
+ before = @original.operands.find_index var
+ after = @operands.find_index var
raise "no #{var} for #{@name}" unless before and after
return before - after
end
@@ -50,7 +49,7 @@ class RubyVM::OperandsUnifications < RubyVM::BareInstructions
case val when '*' then
next nil
else
- type = @original.opes[i][:type]
+ type = @original.operands[i][:type]
expr = RubyVM::Typemap.typecast_to_VALUE type, val
next "#{ptr}[#{i}] == #{expr}"
end
@@ -85,7 +84,7 @@ class RubyVM::OperandsUnifications < RubyVM::BareInstructions
def compose location, spec, template
name = namegen spec
*, argv = *spec
- opes = @original.opes
+ opes = @original.operands
if opes.size != argv.size
raise sprintf("operand size mismatch for %s (%s's: %d, given: %d)",
name, template[:name], opes.size, argv.size)
@@ -130,12 +129,12 @@ class RubyVM::OperandsUnifications < RubyVM::BareInstructions
new h
end
- def self.to_a
+ def self.all
@instances
end
def self.each_group
- to_a.group_by(&:original).each_pair do |k, v|
+ all.group_by(&:original).each_pair do |k, v|
yield k, v
end
end
diff --git a/tool/ruby_vm/models/trace_instructions.rb b/tool/ruby_vm/models/trace_instruction.rb
index 4ed4c8cb42..6a3ad53c44 100644
--- a/tool/ruby_vm/models/trace_instructions.rb
+++ b/tool/ruby_vm/models/trace_instruction.rb
@@ -1,4 +1,3 @@
-#! /your/favourite/path/to/ruby
# -*- Ruby -*-
# -*- frozen_string_literal: true; -*-
# -*- warn_indent: true; -*-
@@ -11,9 +10,9 @@
# details.
require_relative '../helpers/c_escape'
-require_relative 'bare_instructions'
+require_relative 'bare_instruction'
-class RubyVM::TraceInstructions
+class RubyVM::TraceInstruction
include RubyVM::CEscape
attr_reader :name
@@ -61,11 +60,11 @@ class RubyVM::TraceInstructions
private
- @instances = RubyVM::Instructions.map {|i| new i }
+ @instances = (RubyVM::BareInstruction.all +
+ RubyVM::OperandsUnification.all +
+ RubyVM::InstructionsUnification.all).map {|i| new(i) }
- def self.to_a
+ def self.all
@instances
end
-
- RubyVM::Instructions.push(*to_a)
end
diff --git a/tool/ruby_vm/models/typemap.rb b/tool/ruby_vm/models/typemap.rb
index 65ddfea41d..68ef5a41a5 100644
--- a/tool/ruby_vm/models/typemap.rb
+++ b/tool/ruby_vm/models/typemap.rb
@@ -1,4 +1,3 @@
-#! /your/favourite/path/to/ruby
# -*- Ruby -*-
# -*- frozen_string_literal: true; -*-
# -*- warn_indent: true; -*-
@@ -12,11 +11,11 @@
RubyVM::Typemap = {
"..." => %w[. TS_VARIABLE],
- "CALL_CACHE" => %w[E TS_CALLCACHE],
- "CALL_INFO" => %w[C TS_CALLINFO],
+ "CALL_DATA" => %w[C TS_CALLDATA],
"CDHASH" => %w[H TS_CDHASH],
- "GENTRY" => %w[G TS_GENTRY],
"IC" => %w[K TS_IC],
+ "IVC" => %w[A TS_IVC],
+ "ICVARC" => %w[J TS_ICVARC],
"ID" => %w[I TS_ID],
"ISE" => %w[T TS_ISE],
"ISEQ" => %w[S TS_ISEQ],
@@ -25,6 +24,7 @@ RubyVM::Typemap = {
"lindex_t" => %w[L TS_LINDEX],
"rb_insn_func_t" => %w[F TS_FUNCPTR],
"rb_num_t" => %w[N TS_NUM],
+ "RB_BUILTIN" => %w[R TS_BUILTIN],
}
# :FIXME: should this method be here?
diff --git a/tool/ruby_vm/models/zjit_instruction.rb b/tool/ruby_vm/models/zjit_instruction.rb
new file mode 100644
index 0000000000..04764e4c61
--- /dev/null
+++ b/tool/ruby_vm/models/zjit_instruction.rb
@@ -0,0 +1,56 @@
+require_relative '../helpers/c_escape'
+require_relative 'bare_instruction'
+
+# Profile YARV instructions to optimize code generated by ZJIT
+class RubyVM::ZJITInstruction
+ include RubyVM::CEscape
+
+ attr_reader :name
+
+ def initialize(orig)
+ @orig = orig
+ @name = as_tr_cpp "zjit @ #{@orig.name}"
+ end
+
+ def pretty_name
+ return sprintf "%s(...)(...)(...)", @name
+ end
+
+ def jump_destination
+ return @orig.name
+ end
+
+ def bin
+ return sprintf "BIN(%s)", @name
+ end
+
+ def width
+ return @orig.width
+ end
+
+ def operands_info
+ return @orig.operands_info
+ end
+
+ def rets
+ return ['...']
+ end
+
+ def pops
+ return ['...']
+ end
+
+ def attributes
+ return []
+ end
+
+ def has_attribute?(*)
+ return false
+ end
+
+ @instances = RubyVM::BareInstruction.all.filter(&:zjit_profile?).map {|i| new(i) }
+
+ def self.all
+ @instances
+ end
+end