diff options
author | Jari Vetoniemi <jari.vetoniemi@indooratlas.com> | 2020-03-16 18:49:26 +0900 |
---|---|---|
committer | Jari Vetoniemi <jari.vetoniemi@indooratlas.com> | 2020-03-30 00:39:06 +0900 |
commit | fcbf63e62c627deae76c1b8cb8c0876c536ed811 (patch) | |
tree | 64cb17de3f41a2b6fef2368028fbd00349946994 /jni/ruby/template |
Fresh start
Diffstat (limited to 'jni/ruby/template')
24 files changed, 1900 insertions, 0 deletions
diff --git a/jni/ruby/template/Doxyfile.tmpl b/jni/ruby/template/Doxyfile.tmpl new file mode 100644 index 0000000..2fb7588 --- /dev/null +++ b/jni/ruby/template/Doxyfile.tmpl @@ -0,0 +1,265 @@ +# Doxyfile 1.5.7 +<% +srcdir = miniruby = nil +opt = OptionParser.new do |o| + o.on('--srcdir=SRCDIR') {|v| srcdir = v} + o.on('--miniruby=MINIRUBY') {|v| miniruby = v} + o.order!(ARGV) +end +srcdir ||= File.dirname(File.dirname(__FILE__)) +load 'rbconfig.rb' +unless miniruby + miniruby = './miniruby$(EXEEXT) -I$(srcdir)/lib -I$(EXTOUT)/common -I./-' + RbConfig.expand(miniruby, RbConfig::CONFIG.merge("srcdir"=>srcdir)) +end +dot = RbConfig::CONFIG['DOT'] || "" +have_dot = dot.empty? ? "NO" : "YES" +%> +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = Ruby +PROJECT_NUMBER = <%=RUBY_VERSION%><%= RUBY_PATCHLEVEL < 0 ? 'dev' : "p#{RUBY_PATCHLEVEL}" %> (<%=RUBY_RELEASE_DATE%> revision <%=RUBY_REVISION%>) +STRIP_FROM_PATH = <%=srcdir%> +FILE_VERSION_FILTER = "<%=miniruby%> <%=srcdir%>/tool/file2lastrev.rb -q" +INPUT = <%=srcdir%> . +INPUT_FILTER = "<%=miniruby%> <%=srcdir%>/tool/strip-rdoc.rb" + +DOXYFILE_ENCODING = UTF-8 +OUTPUT_DIRECTORY = doc/capi +CREATE_SUBDIRS = YES +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = YES +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +QT_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO +SYMBOL_CACHE_SIZE = 0 +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = YES +INTERNAL_DOCS = YES +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +LAYOUT_FILE = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c *.h *.y *.def +RECURSIVE = YES +EXCLUDE = ext/dl/callback ccan +EXCLUDE_SYMLINKS = YES +EXCLUDE_PATTERNS = *.src doc enc build */ext/-test-/* tmp test yarvtest lib bootstraptest spec .ext .git .svn extconf.h *prelude.c encdb.h transdb.h insns.def +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = <%=srcdir%>/doc/images +FILTER_PATTERNS = +FILTER_SOURCE_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_DYNAMIC_SECTIONS = NO +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHG_LOCATION = +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +FORMULA_FONTSIZE = 10 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = <%=srcdir%> <%=srcdir%>/include +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = <%= have_dot %> +DOT_FONTNAME = FreeSans +DOT_FONTPATH = +CLASS_GRAPH = NO +COLLABORATION_GRAPH = NO +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = NO +DIRECTORY_GRAPH = NO +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/jni/ruby/template/GNUmakefile.in b/jni/ruby/template/GNUmakefile.in new file mode 100644 index 0000000..d9932c0 --- /dev/null +++ b/jni/ruby/template/GNUmakefile.in @@ -0,0 +1,6 @@ +override MFLAGS := $(filter-out -j%,$(MFLAGS)) +include Makefile +-include uncommon.mk +include $(srcdir)/defs/gmake.mk + +GNUmakefile: $(srcdir)/template/GNUmakefile.in diff --git a/jni/ruby/template/encdb.h.tmpl b/jni/ruby/template/encdb.h.tmpl new file mode 100644 index 0000000..9cbb1f0 --- /dev/null +++ b/jni/ruby/template/encdb.h.tmpl @@ -0,0 +1,91 @@ +<% +# +# OnigEncodingDefine(foo, Foo) = { +# .. +# "Shift_JIS", /* Canonical Name */ +# .. +# }; +# ENC_ALIAS("SJIS", "Shift_JIS") +# ENC_REPLICATE("Windows-31J", "Shift_JIS") +# ENC_ALIAS("CP932", "Windows-31J") +# + +def check_duplication(defs, name, fn, line) + if defs[name] + raise ArgumentError, "%s:%d: encoding %s is already registered(%s:%d)" % + [fn, line, name, *defs[name]] + else + defs[name.upcase] = [fn,line] + end +end + +lines = [] +BUILTIN_ENCODINGS = { + 'ASCII-8BIT' => 0, + 'UTF-8' => 1, + 'US-ASCII' => 2, +} +encodings = %w[ASCII-8BIT UTF-8 US-ASCII] # BUILTIN_ENCODINGS.keys is not available on cross compiling and used ruby 1.8 +count = encodings.size +defs = {} +encdirs = ARGV.dup +encdirs << 'enc' if encdirs.empty? +files = {} +encdirs.each do |encdir| + next unless File.directory?(encdir) + Dir.open(encdir) {|d| d.grep(/.+\.[ch]\z/)}.sort_by {|e| + e.scan(/(\d+)|(\D+)/).map {|n,a| a||[n.size,n.to_i]}.flatten + }.each do |fn| + next if files[fn] + files[fn] = true + open(File.join(encdir,fn)) do |f| + name = nil + f.each_line do |line| + if (/^OnigEncodingDefine/ =~ line)..(/"(.*?)"/ =~ line) + if $1 + if name + lines << %[ENC_SET_BASE("#$1", "#{name}");] + else + name = $1 + end + check_duplication(defs, $1, fn, $.) + next if BUILTIN_ENCODINGS[name] + encodings << $1 + count += 1 + end + else + case line + when /^\s*rb_enc_register\(\s*"([^"]+)"/ + count += 1 + line = nil + encodings << $1 + when /^ENC_REPLICATE\(\s*"([^"]+)"\s*,\s*"([^"]+)"/ + raise ArgumentError, + '%s:%d: ENC_REPLICATE: %s is not defined yet. (replica %s)' % + [fn, $., $2, $1] unless defs[$2.upcase] + count += 1 + when /^ENC_ALIAS\(\s*"([^"]+)"\s*,\s*"([^"]+)"/ + raise ArgumentError, + '%s:%d: ENC_ALIAS: %s is not defined yet. (alias %s)' % + [fn, $., $2, $1] unless defs[$2.upcase] + when /^ENC_DUMMY\w*\(\s*"([^"]+)"/ + count += 1 + else + next + end + check_duplication(defs, $1, fn, $.) + lines << line.sub(/;.*/m, "").chomp + ";" if line + end + end + end + end +end +encodings.each_with_index do |e, i| +%>ENC_DEFINE("<%=e%>"); +% end +% encidx = encodings.size - 1 +% lines.each do |line| +<%=line%> +% end + +#define ENCODING_COUNT <%=count%> diff --git a/jni/ruby/template/fake.rb.in b/jni/ruby/template/fake.rb.in new file mode 100644 index 0000000..6f5de50 --- /dev/null +++ b/jni/ruby/template/fake.rb.in @@ -0,0 +1,28 @@ +baseruby="@BASERUBY@" +ruby="${RUBY-$baseruby}" +"eval" "{" \ +"`expr \"$ruby\" : echo > /dev/null || echo exec`" \ +"$ruby" '-r"`expr \"$0\" : / > /dev/null || pwd`/${0#/}" "$@";' \ +"}" || "exit" "$?" +ruby=ruby +class Object + remove_const :CROSS_COMPILING if defined?(CROSS_COMPILING) + CROSS_COMPILING = RUBY_PLATFORM + remove_const :RUBY_PLATFORM + remove_const :RUBY_VERSION + remove_const :RUBY_RELEASE_DATE + remove_const :RUBY_DESCRIPTION if defined?(RUBY_DESCRIPTION) + RUBY_PLATFORM = "@arch@" + RUBY_VERSION = "@RUBY_PROGRAM_VERSION@" + RUBY_RELEASE_DATE = "@RUBY_RELEASE_DATE@" + RUBY_DESCRIPTION = "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]" +end +builddir = File.dirname(__FILE__) +top_srcdir = "@abs_top_srcdir@" +if /mingw/ =~ RUBY_PLATFORM + # convert MSYS path to Windows path + top_srcdir.sub!(/\A\/([a-z])\//, '\\1:/') +end +$:.unshift(File.expand_path(builddir)) +fake = File.join(top_srcdir, "tool/fake.rb") +eval(File.read(fake), nil, fake) diff --git a/jni/ruby/template/id.c.tmpl b/jni/ruby/template/id.c.tmpl new file mode 100644 index 0000000..4ee0499 --- /dev/null +++ b/jni/ruby/template/id.c.tmpl @@ -0,0 +1,27 @@ +%# -*- c -*- +/* DO NOT EDIT THIS FILE DIRECTLY */ +/********************************************************************** + + id.c - + + $Author: nobu $ + created at: Wed Dec 5 02:36:10 2012 + + Copyright (C) 2004-2007 Koichi Sasada + +**********************************************************************/ +<% +defs = File.join(File.dirname(File.dirname(erb.filename)), "defs/id.def") +ids = eval(File.read(defs), binding, defs) +%> +static void +Init_id(void) +{ +#undef rb_intern +#define rb_intern(str) rb_intern_const(str) + rb_encoding *enc = rb_usascii_encoding(); + +% ids[:predefined].each do |token, name| + REGISTER_SYMID(id<%=token%>, "<%=name%>"); +% end +} diff --git a/jni/ruby/template/id.h.tmpl b/jni/ruby/template/id.h.tmpl new file mode 100644 index 0000000..1c645ca --- /dev/null +++ b/jni/ruby/template/id.h.tmpl @@ -0,0 +1,118 @@ +%# -*- c -*- +/* DO NOT EDIT THIS FILE DIRECTLY */ +/********************************************************************** + + id.h - + + $Author: nobu $ + created at: Sun Oct 19 21:12:51 2008 + + Copyright (C) 2007 Koichi Sasada + +**********************************************************************/ +<% +require 'optparse' + +op_id_offset = 128 + +token_op_ids = %w[ + tDOT2 tDOT3 tUPLUS tUMINUS tPOW tDSTAR tCMP tLSHFT tRSHFT + tLEQ tGEQ tEQ tEQQ tNEQ tMATCH tNMATCH tAREF tASET + tCOLON2 tCOLON3 tANDOP tOROP +] + +defs = File.join(File.dirname(File.dirname(erb.filename)), "defs/id.def") +ids = eval(File.read(defs), binding, defs) +types = ids.keys.grep(/^[A-Z]/) +%> +#ifndef RUBY_ID_H +#define RUBY_ID_H + +enum ruby_id_types { + RUBY_ID_STATIC_SYM = 0x01, + RUBY_ID_LOCAL = 0x00, + RUBY_ID_INSTANCE = (0x01<<1), + RUBY_ID_GLOBAL = (0x03<<1), + RUBY_ID_ATTRSET = (0x04<<1), + RUBY_ID_CONST = (0x05<<1), + RUBY_ID_CLASS = (0x06<<1), + RUBY_ID_JUNK = (0x07<<1), + RUBY_ID_INTERNAL = RUBY_ID_JUNK, + RUBY_ID_SCOPE_SHIFT = 4, + RUBY_ID_SCOPE_MASK = (~(~0U<<(RUBY_ID_SCOPE_SHIFT-1))<<1) +}; + +#define ID_STATIC_SYM RUBY_ID_STATIC_SYM +#define ID_SCOPE_SHIFT RUBY_ID_SCOPE_SHIFT +#define ID_SCOPE_MASK RUBY_ID_SCOPE_MASK +#define ID_LOCAL RUBY_ID_LOCAL +#define ID_INSTANCE RUBY_ID_INSTANCE +#define ID_GLOBAL RUBY_ID_GLOBAL +#define ID_ATTRSET RUBY_ID_ATTRSET +#define ID_CONST RUBY_ID_CONST +#define ID_CLASS RUBY_ID_CLASS +#define ID_JUNK RUBY_ID_JUNK +#define ID_INTERNAL RUBY_ID_INTERNAL + +#define ID2ATTRSET(id) (((id)&~ID_SCOPE_MASK)|ID_ATTRSET) + +#define symIFUNC ID2SYM(idIFUNC) +#define symCFUNC ID2SYM(idCFUNC) + +% token_op_ids.each_with_index do |token, index| +#define RUBY_TOKEN_<%=token[/\At(.+)\z/, 1]%> <%=op_id_offset + index%> +% end +#define RUBY_TOKEN(t) RUBY_TOKEN_##t + +enum ruby_method_ids { + idDot2 = RUBY_TOKEN(DOT2), + idDot3 = RUBY_TOKEN(DOT3), + idUPlus = RUBY_TOKEN(UPLUS), + idUMinus = RUBY_TOKEN(UMINUS), + idPow = RUBY_TOKEN(POW), + idCmp = RUBY_TOKEN(CMP), + idPLUS = '+', + idMINUS = '-', + idMULT = '*', + idDIV = '/', + idMOD = '%', + idLT = '<', + idLTLT = RUBY_TOKEN(LSHFT), + idLE = RUBY_TOKEN(LEQ), + idGT = '>', + idGTGT = RUBY_TOKEN(RSHFT), + idGE = RUBY_TOKEN(GEQ), + idEq = RUBY_TOKEN(EQ), + idEqq = RUBY_TOKEN(EQQ), + idNeq = RUBY_TOKEN(NEQ), + idNot = '!', + idBackquote = '`', + idEqTilde = RUBY_TOKEN(MATCH), + idNeqTilde = RUBY_TOKEN(NMATCH), + idAREF = RUBY_TOKEN(AREF), + idASET = RUBY_TOKEN(ASET), + idCOLON2 = RUBY_TOKEN(COLON2), + idANDOP = RUBY_TOKEN(ANDOP), + idOROP = RUBY_TOKEN(OROP), + tPRESERVED_ID_BEGIN = <%=op_id_offset + token_op_ids.size - 1%>, +% ids[:preserved].each do |token| + id<%=token%>, +% end + tPRESERVED_ID_END, +% ids.values_at(*types).flatten.each do |token| + t<%=token%>, +% end + tNEXT_ID, +% types.each do |type| +% types = ids[type] or next +% types.empty? and next +#define TOKEN2<%=type%>ID(n) id##n = ((t##n<<ID_SCOPE_SHIFT)|ID_<%=type%>|ID_STATIC_SYM) +% types.each do |token| + TOKEN2<%=type%>ID(<%=token%>), +% end +% end + tLAST_OP_ID = tPRESERVED_ID_END-1, + idLAST_OP_ID = tLAST_OP_ID >> ID_SCOPE_SHIFT +}; + +#endif /* RUBY_ID_H */ diff --git a/jni/ruby/template/insns.inc.tmpl b/jni/ruby/template/insns.inc.tmpl new file mode 100644 index 0000000..203273f --- /dev/null +++ b/jni/ruby/template/insns.inc.tmpl @@ -0,0 +1,20 @@ +/** -*-c-*- + This file contains YARV instructions list. + + ---- + This file is auto generated by insns2vm.rb + DO NOT TOUCH! + + If you want to fix something, you must edit 'template/insns.inc.tmpl' + or tool/insns2vm.rb + */ + + +/* BIN : Basic Instruction Name */ +#define BIN(n) YARVINSN_##n + +enum ruby_vminsn_type { +<%= insns %> + VM_INSTRUCTION_SIZE = <%= @insns.size %> +}; + diff --git a/jni/ruby/template/insns_info.inc.tmpl b/jni/ruby/template/insns_info.inc.tmpl new file mode 100644 index 0000000..14b4ef5 --- /dev/null +++ b/jni/ruby/template/insns_info.inc.tmpl @@ -0,0 +1,83 @@ +/** -*-c-*- + This file contains instruction information for yarv instruction sequence. + + ---- + This file is auto generated by insns2vm.rb + DO NOT TOUCH! + + If you want to fix something, you must edit 'template/insns_info.inc.tmpl' + or tool/insns2vm.rb + */ + +<%= insn_type_chars %> + +static const char *const insn_name_info[] = { +<%= insn_names %> +}; + +static const char *const insn_operand_info[] = { +<%= operands_info %> +}; + +static const int insn_len_info[] = { +<%= operands_num_info %> +}; + +#ifdef USE_INSN_RET_NUM +static const int insn_stack_push_num_info[] = { +<%= stack_num_info %> +}; +#endif + +#ifdef USE_INSN_STACK_INCREASE +static int +insn_stack_increase(int depth, int insn, VALUE *opes) +{ + switch(insn){ +<%= stack_increase %> + default: + rb_bug("insn_sp_increase: unreachable"); + } + return 0; +} +#endif + +/* some utilities */ + +static int +insn_len(VALUE insn) +{ + return insn_len_info[(int)insn]; +} + +static const char * +insn_name(VALUE insn) +{ + return insn_name_info[(int)insn]; +} + +static const char * +insn_op_types(VALUE insn) +{ + return insn_operand_info[(int)insn]; +} + +static int +insn_op_type(VALUE insn, long pos) +{ + int len = insn_len(insn) - 1; + if(pos < len){ + return insn_operand_info[(int)insn][pos]; + } + else{ + return 0; + } +} + +#ifdef USE_INSN_RET_NUM +static int +insn_ret_num(VALUE insn) +{ + return insn_stack_push_num_info[(int)insn]; +} +#endif diff --git a/jni/ruby/template/known_errors.inc.tmpl b/jni/ruby/template/known_errors.inc.tmpl new file mode 100644 index 0000000..c3aee77 --- /dev/null +++ b/jni/ruby/template/known_errors.inc.tmpl @@ -0,0 +1,14 @@ +/** -*-c-*- + * DO NOT EDIT + * This file is automatically generated by tool/generic_erb.rb from + * template/known_errors.inc.tmpl and defs/known_errors.def. + */ + +% error_names = ARGF.read.split(/\s+/) +% error_names.each do |name| +#ifdef <%=name%> + defined_error("<%=name%>", <%=name%>) +#else + undefined_error("<%=name%>") +#endif +% end diff --git a/jni/ruby/template/minsns.inc.tmpl b/jni/ruby/template/minsns.inc.tmpl new file mode 100644 index 0000000..54b1928 --- /dev/null +++ b/jni/ruby/template/minsns.inc.tmpl @@ -0,0 +1,14 @@ +/** -*-c-*- + This file contains YARV instructions list, to define YARVCore::Instructions. + + ---- + This file is auto generated by insns2vm.rb + DO NOT TOUCH! + + If you want to fix something, you must edit 'template/minsns.inc.tmpl' + or tool/insns2vm.rb + */ + +<%= defs %> + + diff --git a/jni/ruby/template/opt_sc.inc.tmpl b/jni/ruby/template/opt_sc.inc.tmpl new file mode 100644 index 0000000..41492b2 --- /dev/null +++ b/jni/ruby/template/opt_sc.inc.tmpl @@ -0,0 +1,32 @@ +/* -*-c-*- *********************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/** + This file is for threaded code. + + ---- + This file is auto generated by insns2vm.rb + DO NOT TOUCH! + + If you want to fix something, you must edit 'template/opt_sc.inc.tmpl' + or tool/insns2vm.rb + */ + +#define SC_STATE_SIZE 6 + +#define SCS_XX 1 +#define SCS_AX 2 +#define SCS_BX 3 +#define SCS_AB 4 +#define SCS_BA 5 + +#define SC_ERROR 0xffffffff + +static const VALUE sc_insn_info[][SC_STATE_SIZE] = { +<%= sc_insn_info %> +}; + +static const VALUE sc_insn_next[] = { +<%= sc_insn_next %> +}; + diff --git a/jni/ruby/template/optinsn.inc.tmpl b/jni/ruby/template/optinsn.inc.tmpl new file mode 100644 index 0000000..3c4f732 --- /dev/null +++ b/jni/ruby/template/optinsn.inc.tmpl @@ -0,0 +1,30 @@ +/* -*-c-*- *********************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/** + This file is for threaded code. + + ---- + This file is auto generated by insns2vm.rb + DO NOT TOUCH! + + If you want to fix something, you must edit 'template/optinsn.inc.tmpl' + or tool/insns2vm.rb + */ + +static INSN * +insn_operands_unification(INSN *insnobj){ +#ifdef OPT_OPERANDS_UNIFICATION + /* optimize rule */ + switch(insnobj->insn_id){ + +<%= rule %> + + default: + /* do nothing */; + break; + } +#endif + return insnobj; +} + diff --git a/jni/ruby/template/optunifs.inc.tmpl b/jni/ruby/template/optunifs.inc.tmpl new file mode 100644 index 0000000..af313a9 --- /dev/null +++ b/jni/ruby/template/optunifs.inc.tmpl @@ -0,0 +1,35 @@ +/* -*-c-*- *********************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/** + This file is for threaded code. + + ---- + This file is auto generated by insns2vm.rb + DO NOT TOUCH! + + If you want to fix something, you must edit 'template/optunifs.inc.tmpl' + or tool/insns2vm.rb + */ + +/* + static const int UNIFIED_insn_name_1[] = {id, size, ...}; + static const int UNIFIED_insn_name_2[] = {id, size, ...}; + ... + + static const int *const UNIFIED_insn_name[] = {size, + UNIFIED_insn_name_1, + UNIFIED_insn_name_2, ...}; + ... + + static const int *const *const unified_insns_data[] = { + UNIFIED_insn_nameA, + UNIFIED_insn_nameB, ...}; + */ + +<%= unif_insns_each %> +<%= unif_insns %> +<%= unif_insns_data %> + +#undef GET_INSN_NAME + diff --git a/jni/ruby/template/prelude.c.tmpl b/jni/ruby/template/prelude.c.tmpl new file mode 100644 index 0000000..8f331d9 --- /dev/null +++ b/jni/ruby/template/prelude.c.tmpl @@ -0,0 +1,178 @@ +<% +# This file is interpreted by $(BASERUBY) and miniruby. +# $(BASERUBY) is used for miniprelude.c. +# miniruby is used for prelude.c. +# Since $(BASERUBY) may be older than Ruby 1.9, +# Ruby 1.9 feature should not be used. + +class Prelude + C_ESC = { + "\\" => "\\\\", + '"' => '\"', + "\n" => '\n', + } + + 0x00.upto(0x1f) {|ch| C_ESC[[ch].pack("C")] ||= "\\%03o" % ch } + 0x7f.upto(0xff) {|ch| C_ESC[[ch].pack("C")] = "\\%03o" % ch } + C_ESC_PAT = Regexp.union(*C_ESC.keys) + + def c_esc(str) + '"' + str.gsub(C_ESC_PAT) { C_ESC[$&] } + '"' + end + def prelude_base(filename) + filename.chomp(".rb") + end + def prelude_name(filename) + "<internal:" + prelude_base(filename) + ">" + end + + def initialize(init_name, preludes, vpath) + @init_name = init_name + @have_sublib = false + @vpath = vpath + @preludes = {} + @mains = preludes.map {|filename| translate(filename)[0]} + @preludes.delete_if {|_, (_, _, lines, sub)| sub && lines.empty?} + end + + def translate(filename, sub = false) + idx = @preludes[filename] + return idx if idx + lines = [] + result = [@preludes.size, @vpath.strip(filename), lines, sub] + @vpath.foreach(filename) do |line| + @preludes[filename] ||= result + line.sub!(/(?:^|\s+)\#(?:$|[#\s].*)/, '') + line.sub!(/require(_relative)?\s*\(?\s*(["'])(.*?)(?:\.rb)?\2\)?/) do + orig, rel, path = $&, $2, $3 + if rel + path = File.join(File.dirname(filename), path) + nil while path.gsub!(%r'(\A|/)(?!\.\.?/)[^/]+/\.\.(?:/|\z)', '') + end + path = translate("#{path}.rb", true) rescue nil + if path + @have_sublib = true + "TMP_RUBY_PREFIX.require(#{path[0]})" + else + orig + end + end + lines << c_esc(line) + end + result + end +end +Prelude.new(output && output[/\w+(?=_prelude.c\b)/] || 'prelude', ARGV, vpath).instance_eval do +-%> +/* -*-c-*- + THIS FILE WAS AUTOGENERATED BY template/prelude.c.tmpl. DO NOT EDIT. + + sources: <%= @preludes.map {|n,*| prelude_base(n)}.join(', ') %> +*/ +%unless @preludes.empty? +#include "ruby/ruby.h" +#include "internal.h" +#include "vm_core.h" + +% preludes = @preludes.values.sort +% preludes.each {|i, prelude, lines, sub| + +static const char prelude_name<%=i%>[] = <%=c_esc(prelude_name(*prelude))%>; +static const char prelude_code<%=i%>[] = +% lines.each {|line| +<%=line%> +% } +; +% } + +% if @have_sublib +#define PRELUDE_COUNT <%=preludes.size%> + +struct prelude_env { + volatile VALUE prefix_path; +#if PRELUDE_COUNT > 0 + char loaded[PRELUDE_COUNT]; +#endif +}; + +static VALUE +prelude_prefix_path(VALUE self) +{ + struct prelude_env *ptr = DATA_PTR(self); + return ptr->prefix_path; +} +% end + +% unless preludes.empty? +static void +prelude_eval(VALUE code, VALUE name, VALUE line) +{ + rb_iseq_eval(rb_iseq_compile_with_option(code, name, Qnil, line, 0, Qtrue)); +} +% end + +% if @have_sublib +static VALUE +prelude_require(VALUE self, VALUE nth) +{ + struct prelude_env *ptr = DATA_PTR(self); + VALUE code, name; + int n = FIX2INT(nth); + + if (n > PRELUDE_COUNT) return Qfalse; + if (ptr->loaded[n]) return Qfalse; + ptr->loaded[n] = 1; + switch (n) { +% @preludes.each_value do |i, prelude, lines, sub| +% if sub + case <%=i%>: + code = rb_usascii_str_new(prelude_code<%=i%>, sizeof(prelude_code<%=i%>) - 1); + name = rb_usascii_str_new(prelude_name<%=i%>, sizeof(prelude_name<%=i%>) - 1); + break; +% end +% end + default: + return Qfalse; + } + prelude_eval(code, name, INT2FIX(1)); + return Qtrue; +} + +% end +%end +void +Init_<%=@init_name%>(void) +{ +%unless @preludes.empty? +% if @have_sublib + struct prelude_env memo; + ID name = rb_intern("TMP_RUBY_PREFIX"); + VALUE prelude = Data_Wrap_Struct(rb_cData, 0, 0, &memo); + + memo.prefix_path = rb_const_remove(rb_cObject, name); + rb_const_set(rb_cObject, name, prelude); + rb_define_singleton_method(prelude, "to_s", prelude_prefix_path, 0); +% end +% if @have_sublib + memset(memo.loaded, 0, sizeof(memo.loaded)); + rb_define_singleton_method(prelude, "require", prelude_require, 1); +% end +% preludes.each do |i, prelude, lines, sub| +% next if sub + prelude_eval( + rb_usascii_str_new(prelude_code<%=i%>, sizeof(prelude_code<%=i%>) - 1), + rb_usascii_str_new(prelude_name<%=i%>, sizeof(prelude_name<%=i%>) - 1), + INT2FIX(1)); +% end +% if @have_sublib + rb_gc_force_recycle(prelude); +% end + +#if 0 +% preludes.length.times {|i| + puts(prelude_code<%=i%>); +% } +#endif +%end +} +<%end -%> diff --git a/jni/ruby/template/ruby.pc.in b/jni/ruby/template/ruby.pc.in new file mode 100644 index 0000000..8a2c066 --- /dev/null +++ b/jni/ruby/template/ruby.pc.in @@ -0,0 +1,56 @@ +arch=@arch@ +sitearch=@sitearch@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +libdir=@libdir@ +includedir=@includedir@ +MAJOR=@MAJOR@ +MINOR=@MINOR@ +TEENY=@TEENY@ +ruby_version=@ruby_version@ +RUBY_PROGRAM_VERSION=@RUBY_PROGRAM_VERSION@ +RUBY_BASE_NAME=@RUBY_BASE_NAME@ +RUBY_VERSION_NAME=@RUBY_VERSION_NAME@ +RUBY_SO_NAME=@RUBY_SO_NAME@ +RUBY_INSTALL_NAME=@RUBY_INSTALL_NAME@ +DEFFILE=@DEFFILE@ +archlibdir=@archlibdir@ +sitearchlibdir=@sitearchlibdir@ +archincludedir=@archincludedir@ +sitearchincludedir=@sitearchincludedir@ +ruby=${bindir}/${RUBY_INSTALL_NAME}@EXEEXT@ +rubylibprefix=@rubylibprefix@ +rubyarchprefix=@rubyarchprefix@ +rubysitearchprefix=@rubysitearchprefix@ +rubylibdir=@rubylibdir@ +vendordir=@vendordir@ +sitedir=@sitedir@ +vendorlibdir=@vendorlibdir@ +sitelibdir=@sitelibdir@ +rubyarchdir=@rubyarchdir@ +vendorarchdir=@vendorarchdir@ +sitearchdir=@sitearchdir@ +rubyhdrdir=@rubyhdrdir@ +vendorhdrdir=@vendorhdrdir@ +sitehdrdir=@sitehdrdir@ +rubyarchhdrdir=@rubyarchhdrdir@ +vendorarchhdrdir=@vendorarchhdrdir@ +sitearchhdrdir=@sitearchhdrdir@ +LIBPATH=@LIBPATH@ +LIBRUBY_A=@LIBRUBY_A@ +LIBRUBY_SO=@LIBRUBY_SO@ +LIBRUBY=@LIBRUBY@ +LIBRUBYARG_SHARED=@LIBRUBYARG_SHARED@ +LIBRUBYARG_STATIC=@LIBRUBYARG_STATIC@ +LIBRUBYARG=@LIBRUBYARG@ +LIBS=@LIBS@ +DLDFLAGS=@DLDFLAGS@ + +Name: Ruby +Description: Object Oriented Script Language +Version: ${ruby_version} +URL: http://www.ruby-lang.org +Cflags: -I${rubyarchhdrdir} -I${rubyhdrdir} +Libs: ${DLDFLAGS} ${LIBRUBYARG_SHARED} ${LIBS} +Requires: diff --git a/jni/ruby/template/sizes.c.tmpl b/jni/ruby/template/sizes.c.tmpl new file mode 100644 index 0000000..ac9964d --- /dev/null +++ b/jni/ruby/template/sizes.c.tmpl @@ -0,0 +1,30 @@ +%# -*- c -*- +#include "ruby/ruby.h" +<% +class String + def tr_cpp + strip.upcase.tr_s("^A-Z0-9_*", "_").tr_s("*", "P") + end +end +types = ARGF.grep(/^\s*RUBY_CHECK_SIZEOF\((\w[^\[\],#]*)[^#]*\)/) {$1} +conditions = { + "long long" => 'defined(HAVE_TRUE_LONG_LONG)', +} +%> +void +Init_sizeof(void) +{ + VALUE s = rb_hash_new(); + rb_define_const(rb_define_module("RbConfig"), "SIZEOF", s); + +#define DEFINE(type, size) rb_hash_aset(s, rb_str_new_cstr(#type), INT2FIX(SIZEOF_##size)); + +% types.each do |type| +% cond = conditions[type] +#if SIZEOF_<%= type.tr_cpp %> != 0<%= " && #{cond}" if cond %> + DEFINE(<%= type %>, <%= type.tr_cpp %>); +#endif +% end + +#undef DEFINE +} diff --git a/jni/ruby/template/transdb.h.tmpl b/jni/ruby/template/transdb.h.tmpl new file mode 100644 index 0000000..d0cf101 --- /dev/null +++ b/jni/ruby/template/transdb.h.tmpl @@ -0,0 +1,59 @@ +<% +# +# static const rb_transcoder +# rb_from_US_ASCII = { +# "US-ASCII", "UTF-8", &from_US_ASCII, 1, 0, +# NULL, NULL, +# }; +# + +count = 0 +converters = {} +transdirs = ARGV.dup +transdirs << 'enc/trans' if transdirs.empty? + +transdirs = transdirs.sort_by {|td| + -td.length +}.inject([]) {|tds, td| + next tds unless File.directory?(td) + tds << td if tds.all? {|td2| !File.identical?(td2, td) } + tds +} + +files = {} +names_t = [] +converter_list = [] +transdirs.each do |transdir| + names = Dir.entries(transdir) + names_t += names.map {|n| /(?!\A)\.trans\z/ =~ n ? $` : nil }.compact + names_c = names.map {|n| /(?!\A)\.c\z/ =~ n ? $` : nil }.compact + (names_t & names_c).map {|n| + "#{n}.c" + }.sort_by {|e| + e.scan(/(\d+)|(\D+)/).map {|n,a| a||[n.size,n.to_i]}.flatten + }.each do |fn| + next if files[fn] + files[fn] = true + path = File.join(transdir,fn) + open(path) do |f| + f.each_line do |line| + if (/^static const rb_transcoder/ =~ line)..(/"(.*?)"\s*,\s*"(.*?)"/ =~ line) + if $1 && $2 + from_to = "%s to %s" % [$1, $2] + if converters[from_to] + raise ArgumentError, '%s:%d: transcode "%s" is already registered at %s:%d' % + [path, $., from_to, *converters[from_to].values_at(3, 4)] + else + converters[from_to] = [$1, $2, fn[0..-3], path, $.] + converter_list << from_to + end + end + end + end + end + end +end +converter_list.each do |from_to| + from, to, fn = *converters[from_to] +%>rb_declare_transcoder("<%=from%>", "<%=to%>", "<%=fn%>"); +% end diff --git a/jni/ruby/template/unicode_norm_gen.tmpl b/jni/ruby/template/unicode_norm_gen.tmpl new file mode 100644 index 0000000..955c858 --- /dev/null +++ b/jni/ruby/template/unicode_norm_gen.tmpl @@ -0,0 +1,225 @@ +%# -*- mode: ruby; coding: utf-8 -*- +<% +# Copyright Ayumu Nojima (野島 歩) and Martin J. Dürst (duerst@it.aoyama.ac.jp) + +# Script to generate Ruby data structures used in implementing +# String#unicode_normalize,... + +# Constants for input and ouput directory +InputDataDir = ARGV[0] || 'enc/unicode/data' +unicode_version = InputDataDir[/[\d.]+\z/] + +# convenience methods +class Integer + def to_UTF8() # convert to string, taking legibility into account + if self>0xFFFF + "\\u{#{to_s(16).upcase}}" + elsif self>0x7f + "\\u#{to_s(16).upcase.rjust(4, '0')}" + else + chr.sub(/[\\\"]/, "\\\\\\\&") + end + end +end + +module Enumerable + unless method_defined?(:each_slice) + def each_slice(n) + ary = [] + each do |i| + ary << i + if ary.size >= n + yield ary + ary = [] + end + end + yield ary unless ary.empty? + self + end + end +end + +class Array + def to_UTF8() collect {|c| c.to_UTF8}.join('') end + + def each_regexp_chars(n = 8) # converts an array of Integers to character ranges + sort.inject([]) do |ranges, value| + if ranges.last and ranges.last[1]+1>=value + ranges.last[1] = value + ranges + else + ranges << [value, value] + end + end.collect do |first, last| + case last-first + when 0 + first.to_UTF8 + when 1 + first.to_UTF8 + last.to_UTF8 + else + first.to_UTF8 + '-' + last.to_UTF8 + end + end.each_slice(n) do |slice| + yield slice.join('') + end + end +end + +# read the file 'CompositionExclusions.txt' +composition_exclusions = vpath.open("#{InputDataDir}/CompositionExclusions.txt") {|f| + base = Regexp.quote(File.basename(f.path, '.*')) + ext = Regexp.quote(File.extname(f.path)) + version = (line = f.gets)[/^# *#{base}-([\d.]+)#{ext}\s*$/, 1] or + abort "No file version in #{f.path}: #{line}" + (unicode_version ||= version) == version or + abort "Unicode version of directory (#{unicode_version}) and file (#{version}) mismatch" + f.grep(/^[A-Z0-9]{4,5}/) {|code| code.hex} +} + +decomposition_table = {} +kompatible_table = {} +combining_class = {} # constant to allow use in Integer#to_UTF8 + +# read the file 'UnicodeData.txt' +vpath.foreach("#{InputDataDir}/UnicodeData.txt") do |line| + codepoint, name, _2, char_class, _4, decomposition, *_rest = line.split(";") + + case decomposition + when /^[0-9A-F]/ + decomposition_table[codepoint.hex] = decomposition.split(' ').collect {|w| w.hex} + when /^</ + kompatible_table[codepoint.hex] = decomposition.split(' ')[1..-1].collect {|w| w.hex} + end + combining_class[codepoint.hex] = char_class.to_i if char_class != "0" + + if name=~/(First|Last)>$/ and (char_class!="0" or decomposition!="") + warn "Unexpected: Character range with data relevant to normalization!" + end +end + +# calculate compositions from decompositions +composition_table = decomposition_table.reject do |character, decomposition| + composition_exclusions.member? character or # predefined composition exclusion + decomposition.length<=1 or # Singleton Decomposition + combining_class[character] or # character is not a Starter + combining_class[decomposition.first] # decomposition begins with a character that is not a Starter +end.invert + +# recalculate composition_exclusions +composition_exclusions = decomposition_table.keys - composition_table.values + +accent_array = combining_class.keys + composition_table.keys.collect {|key| key.last} + +composition_starters = composition_table.keys.collect {|key| key.first} + +hangul_no_trailing = [] +0xAC00.step(0xD7A3, 28) {|c| hangul_no_trailing << c} + +# expand decomposition table values +decomposition_table.each do |key, value| + position = 0 + while position < value.length + if decomposition = decomposition_table[value[position]] + decomposition_table[key] = value = value.dup # avoid overwriting composition_table key + value[position, 1] = decomposition + else + position += 1 + end + end +end + +# deal with relationship between canonical and kompatibility decompositions +decomposition_table.each do |key, value| + value = value.dup + expanded = false + position = 0 + while position < value.length + if decomposition = kompatible_table[value[position]] + value[position, 1] = decomposition + expanded = true + else + position += 1 + end + end + kompatible_table[key] = value if expanded +end + +while kompatible_table.any? {|key, value| + expanded = value.map {|v| kompatible_table[v] || v}.flatten + kompatible_table[key] = expanded unless value == expanded + } +end + +# generate normalization tables file +%># coding: us-ascii +%# > + +# automatically generated by template/unicode_norm_gen.tmpl + +module UnicodeNormalize + UNICODE_VERSION = "<%=unicode_version%>".freeze + + accents = "" \ + "[<% accent_array.each_regexp_chars do |rx|%><%=rx%>" \ + "<% end%>]" \ + "".freeze + ACCENTS = accents + REGEXP_D_STRING = "#{'' # composition starters and composition exclusions + }" \ + "[<% (composition_table.values+composition_exclusions).each_regexp_chars do |rx|%><%=rx%>" \ + "<% end%>]#{accents}*" \ + "|#{'' # characters that can be the result of a composition, except composition starters + }" \ + "[<% (composition_starters-composition_table.values).each_regexp_chars do |rx|%><%=rx%>" \ + "<% end%>]?#{accents}+" \ + "|#{'' # precomposed Hangul syllables + }" \ + "[\u{AC00}-\u{D7A4}]" \ + "".freeze + REGEXP_C_STRING = "#{'' # composition exclusions + }" \ + "[<% composition_exclusions.each_regexp_chars do |rx|%><%=rx%>" \ + "<% end%>]#{accents}*" \ + "|#{'' # composition starters and characters that can be the result of a composition + }" \ + "[<% (composition_starters+composition_table.values).each_regexp_chars do |rx|%><%=rx%>" \ + "<% end%>]?#{accents}+" \ + "|#{'' # Hangul syllables with separate trailer + }" \ + "[<% hangul_no_trailing.each_regexp_chars do |rx|%><%=rx%>" \ + "<% end%>][\u11A8-\u11C2]" \ + "|#{'' # decomposed Hangul syllables + }" \ + "[\u1100-\u1112][\u1161-\u1175][\u11A8-\u11C2]?" \ + "".freeze + REGEXP_K_STRING = "" \ + "[<% kompatible_table.keys.each_regexp_chars do |rx|%><%=rx%>" \ + "<%end%>]" \ + "".freeze + + class_table = { +% combining_class.each_slice(8) do |slice| + <% slice.each do |key, value|%> "<%=key.to_UTF8%>"=><%=value%><%=%>,<% end%> +% end + } + class_table.default = 0 + CLASS_TABLE = class_table.freeze + + DECOMPOSITION_TABLE = { +% decomposition_table.each_slice(8) do |slice| + <% slice.each do |key, value|%> "<%=key.to_UTF8%>"=>"<%=value.to_UTF8%>".freeze<%=%>,<% end%> +% end + }.freeze + + KOMPATIBLE_TABLE = { +% kompatible_table.each_slice(8) do |slice| + <% slice.each do |key, value|%> "<%=key.to_UTF8%>"=>"<%=value.to_UTF8%>".freeze<%=%>,<% end%> +% end + }.freeze + + COMPOSITION_TABLE = { +% composition_table.each_slice(8) do |slice| + <% slice.each do |key, value|%> "<%=key.to_UTF8%>"=>"<%=value.to_UTF8%>".freeze<%=%>,<% end%> +% end + }.freeze +end diff --git a/jni/ruby/template/verconf.h.tmpl b/jni/ruby/template/verconf.h.tmpl new file mode 100644 index 0000000..5ee8a0e --- /dev/null +++ b/jni/ruby/template/verconf.h.tmpl @@ -0,0 +1,61 @@ +% require './rbconfig' +% C = RbConfig::MAKEFILE_CONFIG.dup +% def C.[](name) str = super and (str unless str.empty?); end +#define RUBY_BASE_NAME "${RUBY_BASE_NAME}" +#define RUBY_VERSION_NAME RUBY_BASE_NAME"-"RUBY_LIB_VERSION +% if C["RUBY_LIB_VERSION_STYLE"] +#define RUBY_LIB_VERSION_STYLE ${RUBY_LIB_VERSION_STYLE} +% elsif !C["RUBY_LIB_VERSION"] +#define RUBY_LIB_VERSION_STYLE 3 /* full */ +% else +#define RUBY_LIB_VERSION "${RUBY_LIB_VERSION}" +% end +#define RUBY_EXEC_PREFIX "<%='${RUBY_EXEC_PREFIX}' if C['RUBY_EXEC_PREFIX']%>" +#define RUBY_LIB_PREFIX "${rubylibprefix}" +% unless (sitearch = C["sitearch"]) == '$(arch)' +#define RUBY_SITEARCH "<%=sitearch%>" +% end +#define RUBY_ARCH_PREFIX_FOR(arch) "${rubyarchprefix}" +#define RUBY_SITEARCH_PREFIX_FOR(arch) "${rubysitearchprefix}" +#define RUBY_LIB "${rubylibdir}" +#define RUBY_ARCH_LIB_FOR(arch) "${rubyarchdir}" +% if C["sitedir"] == "no" +#define NO_RUBY_SITE_LIB 1 +% else +#define RUBY_SITE_LIB "${sitedir}" +#define RUBY_SITE_ARCH_LIB_FOR(arch) "${sitearchdir}" +% end +% if C["vendordir"] == "no" +#define NO_RUBY_VENDOR_LIB 1 +% else +#define RUBY_VENDOR_LIB "${vendordir}" +#define RUBY_VENDOR_ARCH_LIB_FOR(arch) "${vendorarchdir}" +% end +% if C["RUBY_SEARCH_PATH"] +#define RUBY_SEARCH_PATH "${RUBY_SEARCH_PATH}" +% end +% +% R = {} +% R["ruby_version"] = '"RUBY_LIB_VERSION"' +% R["arch"] = '"arch"' +% R["sitearch"] = '"arch"' +% R["vendorlibdir"] = '"RUBY_VENDOR_LIB2"' +% R["sitelibdir"] = '"RUBY_SITE_LIB2"' +% R["vendordir"] = '"RUBY_VENDOR_LIB"' +% R["sitedir"] = '"RUBY_SITE_LIB"' +% R["rubylibdir"] = '"RUBY_LIB"' +% R["rubylibprefix"] = '"RUBY_LIB_PREFIX"' +% R["rubyarchprefix"] = '"RUBY_ARCH_PREFIX_FOR(arch)"' +% R["rubysitearchprefix"] = '"RUBY_SITEARCH_PREFIX_FOR(arch)"' +% R["exec_prefix"] = '"RUBY_EXEC_PREFIX"' +% R["prefix"] = '"RUBY_EXEC_PREFIX"' +% exec_prefix_pat = /\A"#{Regexp.quote(RbConfig::CONFIG['exec_prefix'])}(?=\/|\z)/ +% _erbout.gsub!(/^(#define\s+(\S+)\s+)(.*)/) { +% pre, name, repl = $1, $2, $3 +% pat = %["#{name}"] +% c = C.merge(R.reject {|key, value| key == name or value.include?(pat)}) +% RbConfig.expand(repl, c) +% repl.gsub!(/^""(?!$)|(.)""$/, '\1') +% repl.sub!(exec_prefix_pat, 'RUBY_EXEC_PREFIX"') +% pre + repl +% } diff --git a/jni/ruby/template/vm.inc.tmpl b/jni/ruby/template/vm.inc.tmpl new file mode 100644 index 0000000..11c6d1b --- /dev/null +++ b/jni/ruby/template/vm.inc.tmpl @@ -0,0 +1,29 @@ +/* -*-c-*- *********************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/** + This file is VM main loop. + + ---- + This file is auto generated by insns2vm.rb + DO NOT TOUCH! + + If you want to fix something, you must edit 'insns.def' + */ + +<%= +line = 15 +vm_body.gsub(/\n|__CURRENT_LINE__|__CURRENT_FILE__/){ + e = $& + case e + when '__CURRENT_LINE__' + line.to_s + when '__CURRENT_FILE__' + "vm.inc" + else + line += 1 + e + end +} +%> + diff --git a/jni/ruby/template/vmtc.inc.tmpl b/jni/ruby/template/vmtc.inc.tmpl new file mode 100644 index 0000000..5f1f51a --- /dev/null +++ b/jni/ruby/template/vmtc.inc.tmpl @@ -0,0 +1,18 @@ +/* -*-c-*- *********************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/** + This file is for threaded code. + + ---- + This file is auto generated by insns2vm.rb + DO NOT TOUCH! + + If you want to fix something, you must edit 'template/vmtc.inc.tmpl' + or insns2vm.rb + */ + +static const void *const insns_address_table[] = { +<%= insns_table %> +}; + diff --git a/jni/ruby/template/yarvarch.en b/jni/ruby/template/yarvarch.en new file mode 100644 index 0000000..7a76e25 --- /dev/null +++ b/jni/ruby/template/yarvarch.en @@ -0,0 +1,7 @@ +#title YARV: Yet another RubyVM - Software Architecture + +maybe writing. + +* YARV instruction set + +<%= d %> diff --git a/jni/ruby/template/yarvarch.ja b/jni/ruby/template/yarvarch.ja new file mode 100644 index 0000000..2739ec6 --- /dev/null +++ b/jni/ruby/template/yarvarch.ja @@ -0,0 +1,454 @@ +#title YARVアーキテクチャ +#set author 日本 Ruby の会 ささだこういち + + +- 2005-03-03(Thu) 00:31:12 +0900 いろいろと書き直し + +---- + +* これは? + +[[YARV: Yet Another RubyVM|http://www.atdot.net/yarv]] の 設計メモです。 + + +YARV は、Ruby プログラムのための次の機能を提供します。 + +- Compiler +- VM Generator +- VM (Virtual Machine) +- Assembler +- Dis-Assembler +- (experimental) JIT Compiler +- (experimental) AOT Compiler + + +現在の YARV は Ruby インタプリタの拡張ライブラリとして実装しています。こ +れにより、Ruby インタプリタの必要な機能(パーサ、オブジェクト管理、既存 +の拡張ライブラリ)などがほぼそのまま利用できます。 + +ただし、いくつかのパッチを Ruby インタプリタに当てなければなりません。 + +今後は、Ruby 本体のインタプリタ部分(eval.c)を置き換えることを目指して +開発を継続する予定です。 + + +* Compiler (compile.h, compile.c) + +コンパイラは、Ruby インタプリタのパーサによって生成された構文木(RNode +データによる木)を YARV 命令列に変換します。YARV 命令については後述しま +す。 + +とくに難しいことはしていませんが、スコープなどの開始時にローカル変数の初 +期化などを行い、あとは構文木を辿り変換していきます。 + +変換中は Ruby の Array オブジェクトに YARV 命令オブジェクト、およびオペ +ランドを格納していき、最後に実行できる形に変換します。コンパイラでは、コ +ンパイル中に生成するメモリ領域の管理が問題になることがありますが、YARV +の場合、Ruby インタプリタがすべて面倒をみてくれるのでこの部分は非常に楽 +に作ることができました(ガーベージコレクタによって自動的にメモリ管理をし +てくれるため)。 + +YARV 命令は、命令を示す識別子、オペランドなど、すべて 1 word (マシンで +表現できる自然な値。C 言語ではポインタのサイズ。Ruby インタプリタ用語で +は VALUE のサイズ)で表現されます。そのため、YARV 命令はいわゆる「バイト +コード」ではありません。そのため、YARV の説明などでは「命令列」という用 +語を使っています。 + +1 word であるため、メモリの利用効率は多少悪くなりますが、アクセス速度な +どを考慮すると、本方式が一番いいと考えております。たとえばオペランドをコ +ンスタントプールに格納し、インデックスのみをオペランドで示すことも可能で +すが、間接アクセスになってしまうので性能に影響が出るため、却下しました。 + + +* VM Generator (rb/insns2vm.rb, insns.def) + +rb/insns2vm.rb というスクリプトは、insns.def というファイルを読み込み、 +VM のために必要なファイルを生成します。具体的には、命令を実行する部分を +生成しますが、ほかにもコンパイルに必要な情報、最適化に必要な情報、やアセ +ンブラ、逆アセンブラに必要な情報を示すファイルも生成します。 + + +** 命令記述 + +insns.def には、各命令がどのような命令であるかを記述します。具体的には次 +の情報を記述します。 + +- 命令の名前 +- その命令のカテゴリ、コメント(英語、日本語) +- オペランドの名前 +- その命令実行前にスタックからポップする値 +- その命令実行後にスタックにプッシュする値 +- その命令のロジック(C 言語で記述) + +たとえば、スタックに self をおく putself という命令は次のように記述しま +す。 + +#code +/** + @c put + @e put self. + @j self を置く。 + */ +DEFINE_INSN +putself +() +() +(VALUE val) +{ + val = GET_SELF(); +} +#end + +この場合、オペランドと、スタックからポップする値は無いことになります。命 +令終了後、self をスタックトップに置きたいわけですが、それは val という、 +スタックにプッシュする値として宣言しておいた変数に代入しておくことで、こ +れを変換するとスタックトップに置く C プログラムが生成されます。 + +細かいフォーマットは insns.def の冒頭を参照してください。そんなに難しく +ないと思います。 + +insnhelper.h というファイルに、命令ロジックを記述するために必要なマクロ +が定義されています。また、VM の内部構造に関する定義は vm.h というファイ +ルにあります。 + + +* VM (Virtual Machine, vm.h, vm.c) + +VM は、実際にコンパイルした結果生成される YARV 命令列を実行します。まさ +に、この部分が YARV のキモになり、将来的には eval.c をこの VM で置き換え +たいと考えています。 + +現在の Ruby インタプリタで実行できるすべてのことが、この VM で実現できる +ように作っています(現段階ではまだ完全ではありませんが、そうなるべきです)。 + +VM は、単純なスタックマシンとして実装しています。スレッドひとつにスタッ +クひとつを保持します。スタックの領域はヒープから取得するので、柔軟な領域 +設定が可能です。 + + +** レジスタ + +VM は 5 つの仮想的なレジスタによって制御されます。 + +- PC (Program Counter) +- SP (Stack Pointer) +- CFP (Control Frame Pointer) +- LFP (Local Frame Pointer) +- DFP (Dynamic Frame Pointer) + +PC は現在実行中の命令列の位置を示します。SP はスタックトップの位置を示し +ます。CFP、LFP、DFP はそれぞれフレームの情報を示します。詳細は後述します。 + + +** スタックフレーム + +obsolete (update soon) + + +** フレームデザインについての補足 + +Lisp の処理系などをかんがえると、わざわざブロックローカルフレームとメソ +ッドローカルフレームのようなものを用意するのは奇異に見えるかもしれません。 +あるフレームを、入れ子構造にして、ローカル変数のアクセスはその入れ子を外 +側に辿れば必ずたどり着くことができるからです(つまり、lfp は必要ない)。 + +しかし、Ruby ではいくつか状況が違います。まず、メソッドローカルな情報が +あること、具体的にはブロックとself(callee からみると receiver)です。こ +の情報をそれぞれのフレームにもたせるのは無駄です。 + +また、Ruby2.0 からはブロックローカル変数はなくなります(ブロックローカル +引数は残るので、構造自体はあまり変わりません)。そのため、メソッドローカ +ル変数へのアクセスが頻発することが予想されます。 + +このとき、メソッドローカル変数へのアクセスのたびにフレーム(スコープ)の +リストをたどるのは無駄であると判断し、明示的にメソッドローカルスコープと +ブロックフレームを分離し、ブロックフレームからはメソッドローカルフレーム +が lfpレジスタによって容易にアクセスできるようにしました。 + + +** メソッド呼び出しについて + +メソッド呼び出しは、YARV 命令列で記述されたメソッドか、C で記述されたメ +ソッドかによってディスパッチ手法が変わります。 + +YARV 命令列であった場合、上述したスタックフレームを作成して命令を継続し +ます。とくに VM の関数を再帰呼び出すすることは行ないません。 + +C で記述されたメソッドだった場合、単純にその関数を呼び出します(ただし、 +バックトレースを正しく生成するためにメソッド呼び出しの情報を付加してから +行ないます)。 + +このため、VM 用スタックを別途用意したものの、プログラムによってはマシン +スタックを使い切ってしまう可能性があります(C -> Ruby -> C -> ... という +呼び出しが続いた場合)。これは、現在では避けられない仕様となっています。 + + +** 例外 + +例外は、Java の JVM と同様に例外テーブルを用意することで実現します。例外 +が発生したら、当該フレームを、例外テーブルを検査します。そこで、例外が発 +生したときの PC の値に合致するエントリがあった場合、そのエントリに従って +動作します。もしエントリが見つからなかった場合、スタックを撒き戻してまた +同様にそのスコープの例外テーブルを検査します。 + +また、break、return(ブロック中)、retry なども同様の仕組みで実現します。 + +*** 例外テーブル + +例外テーブルエントリは具体的には次の情報が格納されています。 + +- 対象とする PC の範囲 +- 対象とする例外の種類 +- もし対象となったときにジャンプする先(種類による) +- もし対象となったときに起動するブロックの iseq + + +*** rescue + +rescue 節はブロックとして実現しています。$! の値を唯一の引数として持ちま +す。 + +#code +begin +rescue A +rescue B +rescue C +end +#end + +は、次のような Ruby スクリプトに変換されます。 + +#code +{|err| + case err + when A === err + when B === err + when C === err + else + raise # yarv の命令では throw + end +} +#end + + +*** ensure + +正常系(例外が発生しなかった場合)と異常系(例外が発生したときなど)の2 +種類の命令列が生成されます。正常系では、ただの連続したコード領域としてコ +ンパイルされます。また、異常系ではブロックとして実装します。最後は必ず +throw 命令で締めることになります。 + + +*** break, return(ブロック中)、retry + +break 文、ブロック中の return 文、retry 文は throw 命令としてコンパイル +されます。どこまで戻るかは、break をフックする例外テーブルのエントリが判 +断します。 + + +** 定数の検索 + +定数という名前なのに、Ruby ではコンパイル時に決定しません。というか、い +つまでも再定義可能になっています。 + +定数アクセスのためのRuby記述は次のようになります。 + +#code +Ruby表現: +expr::ID::...::ID +#end + +これは、yarv命令セットでは次のようになります。 + +#code +(expr) +getconstant ID +... +getconstant ID +#end + + +*** 定数検索パス + +もし expr が nil だった場合、定数検索パスに従って定数を検索します。この +挙動は今後 Ruby 2.0 に向けて変更される場合があります。 + ++ クラス、モジュールの動的ネスト関係(プログラムの字面上)をルートまで辿る ++ 継承関係をルート(Object)まで辿る + +このため、クラス、モジュールの動的ネスト関係を保存しなければなりません。 +このために、thread_object には klass_nest_stack というものを用意しました。 +これは、現在のネストの情報を保存します。 + +メソッド定義時、その現在のネスト情報をメソッド定義時に(dupして)加える +ことで、そのメソッドの実行時、そのネスト情報を参照することが可能になりま +す。 + +トップレベルでは、その情報はないことになります。 + +クラス/モジュール定義文実行時は、現在の情報そのものを参照することになり +ます。これは、クラススコープ突入時、その情報をクラス定義文にコピーします +(すでにコピーされていれば、これを行いません)。 + +これにより、動的なネスト情報を統一的に扱うことができます。 + + +** 最適化手法 + +YARV では高速化を目的としているので、さまざまな最適化手法を利用していま +す。詳細は割愛しますが、以下に述べる最適化などを行なっております。 + + +*** threaded code + +GCC の C 言語拡張である値としてのラベルを利用して direct threaded code +を実現しています。 + + +*** Peephole optimization + +いくつかの簡単な最適化をしています。 + + +*** inline method cache + +命令列の中にメソッド検索結果を埋め込みます。 + + +*** inline constant cache + +命令列の中に定数検索結果を埋め込みます。 + + +*** ブロックと Proc オブジェクトの分離 + +ブロック付きメソッド呼び出しが行なわれたときにはすぐにはブロックを Proc +オブジェクトとして生成しません。これにより、必要ない Proc オブジェクトの +生成を抑えています。 + +Proc メソッドは、実際に必要になった時点で作られ、そのときに環境(スコー +プ上に確保された変数など)をヒープに保存します。 + + +*** 特化命令 + +Fixnum 同士の加算などを正直に関数呼び出しによって行なうと、コストがかか +るので、これらのプリミティブな操作を行なうためのメソッド呼び出しは専用命 +令を用意しました。 + + +*** 命令融合 + +複数の命令を 1 命令に変換します。融合命令は opt_insn_unif.def の記述によ +り自動的に生成されます。 + + +*** オペランド融合 + +複数のオペランドを含めた命令を生成します。融合命令は opt_operand.def の +記述によって自動的に生成されます。 + + +*** stack caching + +スタックトップを仮想レジスタに保持するようにします。現在は 2 個の仮想レ +ジスタを想定し、5状態のスタックキャッシングを行ないます。スタックキャッ +シングする命令は自動的に生成されます。 + + +*** JIT Compile + +機械語を切り貼りします。非常に実験的なコードものしか作っておりません。ほ +とんどのプログラムは動きません。 + + +*** AOT Compile + +YARV 命令列を C 言語に変換します。まだ十分な最適化を行なえておりませんが、 +それなりに動きます。rb/aotc.rb がコンパイラです。 + + +* Assembler (rb/yasm.rb) + +YARV 命令列のアセンブラを用意しました。使い方は rb/yasm.rb を参照してく +ださい(まだ、例示してある生成手法のすべてをサポートしているわけではあり +ません)。 + + +* Dis-Assembler (disasm.c) + +YARV 命令列を示すオブジェクト YARVCore::InstructionSequence には disasm +メソッドがあります。これは、命令列を逆アセンブルした文字列を返します。 + + +* YARV 命令セット + +<%= d %> + +* その他 + +** テスト + +test/test_* がテストケースです。一応、ミスなく動くはずです。逆にいうと、 +このテストに記述されている例ではきちんと動作するということです。 + + +** ベンチマーク + +benchmark/bm_* にベンチマークプログラムがおいてあります。 + + +** 今後の予定 + +まだまだやらなければいけないこと、未実装部分がたくさんありますんでやって +いかなければなりません。一番大きな目標は eval.c を置き換えることでしょう +か。 + + +*** Verifier + +YARV 命令列は、ミスがあっても動かしてしまうため危険である可能性がありま +す。そのため、スタックの利用状態をきちんと事前に検証するようなベリファイ +アを用意しなければならないと考えています。 + + +*** Compiled File の構想 + +Ruby プログラムをこの命令セットにシリアライズしたデータ構造をファイルに +出力できるようにしたいと考えています。これを利用して一度コンパイルした命 +令列をファイルに保存しておけば、次回ロード時にはコンパイルの手間、コスト +を省くことができます。 + + +**** 全体構成 + +次のようなファイル構成を考えていますが、まだ未定です。 + +#code +u4 : 4 byte unsigned storage +u2 : 2 byte unsigned storage +u1 : 1 byte unsigned storage + +every storages are little endian :-) + +CompiledFile{ + u4 magic; + + u2 major; + u2 minor; + + u4 character_code; + + u4 constants_pool_count; + ConstantEntry constants_pool[constants_pool_count]; + + u4 block_count; + blockEntry blocks[block_count]; + + u4 method_count; + MethodEntry methods[method_count]; +} +#end + +Java classfile のパクリ。 + diff --git a/jni/ruby/template/yasmdata.rb.tmpl b/jni/ruby/template/yasmdata.rb.tmpl new file mode 100644 index 0000000..a11df0a --- /dev/null +++ b/jni/ruby/template/yasmdata.rb.tmpl @@ -0,0 +1,20 @@ +# -*-ruby-*- +# + +class VM + class InstructionSequence + class Instruction + InsnID2NO = { +<%= insn_id2no %> + } + + def self.id2insn_no id + if InsnID2NO.has_key? id + InsnID2NO[id] + end + end + end + end +end + + |