summaryrefslogtreecommitdiff
path: root/tool/ruby_vm/models/bare_instructions.rb
diff options
context:
space:
mode:
Diffstat (limited to 'tool/ruby_vm/models/bare_instructions.rb')
-rw-r--r--tool/ruby_vm/models/bare_instructions.rb239
1 files changed, 0 insertions, 239 deletions
diff --git a/tool/ruby_vm/models/bare_instructions.rb b/tool/ruby_vm/models/bare_instructions.rb
deleted file mode 100644
index f813760cb6..0000000000
--- a/tool/ruby_vm/models/bare_instructions.rb
+++ /dev/null
@@ -1,239 +0,0 @@
-# -*- Ruby -*-
-# -*- frozen_string_literal: true; -*-
-# -*- warn_indent: true; -*-
-#
-# Copyright (c) 2017 Urabe, Shyouhei. All rights reserved.
-#
-# This file is a part of the programming language Ruby. Permission is hereby
-# granted, to either redistribute and/or modify this file, provided that the
-# conditions mentioned in the file COPYING are met. Consult the file for
-# details.
-
-require_relative '../loaders/insns_def'
-require_relative 'c_expr'
-require_relative 'typemap'
-require_relative 'attribute'
-
-class RubyVM::BareInstructions
- attr_reader :template, :name, :operands, :pops, :rets, :decls, :expr
-
- def initialize opts = {}
- @template = opts[:template]
- @name = opts[:name]
- @loc = opts[:location]
- @sig = opts[:signature]
- @expr = RubyVM::CExpr.new opts[:expr]
- @operands = typesplit @sig[:ope]
- @pops = typesplit @sig[:pop].reject {|i| i == '...' }
- @rets = typesplit @sig[:ret].reject {|i| i == '...' }
- @attrs = opts[:attributes].map {|i|
- RubyVM::Attribute.new i.merge(:insn => self)
- }.each_with_object({}) {|a, h|
- h[a.key] = a
- }
- @attrs_orig = @attrs.dup
- check_attribute_consistency
- predefine_attributes
- end
-
- def pretty_name
- n = @sig[:name]
- o = @sig[:ope].map{|i| i[/\S+$/] }.join ', '
- p = @sig[:pop].map{|i| i[/\S+$/] }.join ', '
- r = @sig[:ret].map{|i| i[/\S+$/] }.join ', '
- return sprintf "%s(%s)(%s)(%s)", n, o, p, r
- end
-
- def bin
- return "BIN(#{name})"
- end
-
- def call_attribute name
- return sprintf 'attr_%s_%s(%s)', name, @name, \
- @operands.map {|i| i[:name] }.compact.join(', ')
- end
-
- def has_attribute? k
- @attrs_orig.has_key? k
- end
-
- def attributes
- return @attrs \
- . sort_by {|k, _| k } \
- . map {|_, v| v }
- end
-
- def width
- return 1 + operands.size
- end
-
- def declarations
- return @variables \
- . values \
- . group_by {|h| h[:type] } \
- . sort_by {|t, v| t } \
- . map {|t, v| [t, v.map {|i| i[:name] }.sort ] } \
- . map {|t, v|
- sprintf("MAYBE_UNUSED(%s) %s", t, v.join(', '))
- }
- end
-
- def preamble
- # preamble makes sense for operand unifications
- return []
- end
-
- def sc?
- # sc stands for stack caching.
- return false
- end
-
- def cast_to_VALUE var, expr = var[:name]
- RubyVM::Typemap.typecast_to_VALUE var[:type], expr
- end
-
- def cast_from_VALUE var, expr = var[:name]
- RubyVM::Typemap.typecast_from_VALUE var[:type], expr
- end
-
- def operands_info
- operands.map {|o|
- c, _ = RubyVM::Typemap.fetch o[:type]
- next c
- }.join
- end
-
- def handles_sp?
- /\b(false|0)\b/ !~ @attrs.fetch('handles_sp').expr.expr
- end
-
- def always_leaf?
- @attrs.fetch('leaf').expr.expr == 'true;'
- end
-
- def leaf_without_check_ints?
- @attrs.fetch('leaf').expr.expr == 'leafness_of_check_ints;'
- end
-
- def handle_canary stmt
- # Stack canary is basically a good thing that we want to add, however:
- #
- # - When the instruction returns variadic number of return values,
- # it is not easy to tell where is the stack top. We can't but
- # skip it.
- #
- # - When the instruction body is empty (like putobject), we can
- # say for 100% sure that canary is a waste of time.
- #
- # So we skip canary for those cases.
- return '' if @sig[:ret].any? {|i| i == '...' }
- return '' if @expr.blank?
- return " #{stmt};\n"
- end
-
- def inspect
- sprintf "#<%s %s@%s:%d>", self.class.name, @name, @loc[0], @loc[1]
- end
-
- def has_ope? var
- 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
-
- 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, \
- name: k, \
- type: t, \
- location: [], \
- expr: v.to_s + ';'
- return @attrs[k] ||= attr
- end
-
- def predefine_attributes
- # 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', 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
- end
-
- def default_definition_of_handles_sp
- # Insn with ISEQ should yield it; can handle sp.
- return operands.any? {|o| o[:type] == 'ISEQ' }
- end
-
- def default_definition_of_leaf
- # Insn that handles SP can never be a leaf.
- if not has_attribute? 'handles_sp' then
- return ! default_definition_of_handles_sp
- elsif handles_sp? then
- return "! #{call_attribute 'handles_sp'}"
- else
- return true
- end
- end
-
- def typesplit a
- @variables ||= {}
- a.map do |decl|
- md = %r'
- (?<comment> /[*] [^*]* [*]+ (?: [^*/] [^*]* [*]+ )* / ){0}
- (?<ws> \g<comment> | \s ){0}
- (?<ident> [_a-zA-Z] [0-9_a-zA-Z]* ){0}
- (?<type> (?: \g<ident> \g<ws>+ )* \g<ident> ){0}
- (?<var> \g<ident> ){0}
- \G \g<ws>* \g<type> \g<ws>+ \g<var>
- 'x.match(decl)
- @variables[md['var']] ||= {
- decl: decl,
- type: md['type'],
- name: md['var'],
- }
- end
- end
-
- @instances = RubyVM::InsnsDef.map {|h|
- new h.merge(:template => h)
- }
-
- def self.fetch name
- @instances.find do |insn|
- insn.name == name
- end or raise IndexError, "instruction not found: #{name}"
- end
-
- def self.to_a
- @instances
- end
-end