зеркало из https://github.com/github/ruby.git
Родитель
09b4236f17
Коммит
31f4b2d86b
30
common.mk
30
common.mk
|
@ -237,10 +237,6 @@ $(srcdir)/lib/ruby_vm/mjit/instruction.rb: $(tooldir)/insns2vm.rb $(tooldir)/rub
|
|||
$(ECHO) generating $@
|
||||
$(Q) $(BASERUBY) -Ku $(tooldir)/insns2vm.rb --basedir="$(srcdir)" $(INSNS2VMOPT) $@
|
||||
|
||||
mjit-headers: $(MJIT_SUPPORT)-mjit-headers
|
||||
no-mjit-headers: PHONY
|
||||
yes-mjit-headers: mjit_config.h PHONY
|
||||
|
||||
mjit.$(OBJEXT): mjit_config.h
|
||||
mjit_config.h: Makefile
|
||||
|
||||
|
@ -248,29 +244,6 @@ mjit_config.h: Makefile
|
|||
mjit-bindgen:
|
||||
$(Q) $(BASERUBY) -rrubygems -C $(srcdir)/tool/mjit bindgen.rb $(CURDIR)
|
||||
|
||||
# These rules using MJIT_HEADER_SUFFIX must be in common.mk, not
|
||||
# Makefile.in, in order to override the macro in defs/universal.mk.
|
||||
|
||||
# Other `-Dxxx`s preceding `-DMJIT_HEADER` will be removed in transform_mjit_header.rb.
|
||||
# So `-DMJIT_HEADER` should be passed first when rb_mjit_header.h is generated.
|
||||
$(TIMESTAMPDIR)/$(MJIT_HEADER:.h=)$(MJIT_HEADER_SUFFIX).time: probes.h vm.$(OBJEXT) \
|
||||
$(TIMESTAMPDIR)/$(arch)/.time $(tooldir)/mjit_tabs.rb $(PREP) $(RBCONFIG)
|
||||
$(ECHO) building $(@F:.time=.h)
|
||||
$(Q)$(MINIRUBY) $(tooldir)/mjit_tabs.rb "$(MJIT_TABS)" \
|
||||
$(CPP) -DMJIT_HEADER $(MJIT_HEADER_FLAGS) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(srcdir)/vm.c $(CPPOUTFLAG)$(@F:.time=.h).new
|
||||
$(Q) $(IFCHANGE) "--timestamp=$@" $(@F:.time=.h) $(@F:.time=.h).new
|
||||
|
||||
$(MJIT_HEADER:.h=)$(MJIT_HEADER_SUFFIX).h: $(TIMESTAMPDIR)/$(MJIT_HEADER:.h=)$(MJIT_HEADER_SUFFIX).time
|
||||
|
||||
$(MJIT_MIN_HEADER:.h=)$(MJIT_HEADER_SUFFIX).h: \
|
||||
$(TIMESTAMPDIR)/$(MJIT_HEADER:.h=)$(MJIT_HEADER_SUFFIX).time \
|
||||
$(tooldir)/transform_mjit_header.rb $(PREP) \
|
||||
$(MJIT_HEADER:.h=)$(MJIT_HEADER_SUFFIX).h
|
||||
$(ECHO) building $@
|
||||
$(Q)$(MINIRUBY) $(tooldir)/transform_mjit_header.rb "$(CC) $(CFLAGS) -w" $(MJIT_HEADER:.h=)$(MJIT_HEADER_ARCH).h $@
|
||||
$(Q) $(MAKEDIRS) $(MJIT_HEADER_INSTALL_DIR)
|
||||
$(Q) $(MAKE_LINK) $@ $(MJIT_HEADER_INSTALL_DIR)/$(@F)
|
||||
|
||||
.PHONY: showflags
|
||||
exts enc trans: $(SHOWFLAGS)
|
||||
showflags:
|
||||
|
@ -684,8 +657,7 @@ clean-srcs-local::
|
|||
$(Q)$(RM) parse.c parse.h lex.c enc/trans/newline.c revision.h
|
||||
$(Q)$(RM) id.c id.h probes.dmyh probes.h
|
||||
$(Q)$(RM) encdb.h transdb.h verconf.h ruby-runner.h
|
||||
$(Q)$(RM) mjit_config.h rb_mjit_header.h
|
||||
$(Q)$(RM) $(MJIT_MIN_HEADER) $(MJIT_MIN_HEADER:.h=)$(MJIT_HEADER_SUFFIX:%=*).h
|
||||
$(Q)$(RM) mjit_config.h
|
||||
|
||||
realclean-srcs-local:: clean-srcs-local
|
||||
$(Q)$(CHDIR) $(srcdir) && $(RM) \
|
||||
|
|
10
configure.ac
10
configure.ac
|
@ -797,8 +797,6 @@ AS_IF([test "$GCC" = yes], [
|
|||
[@%:@include <stdio.h>])
|
||||
])
|
||||
|
||||
: ${MJIT_HEADER_FLAGS='-P -dD'}
|
||||
|
||||
# -fstack-protector
|
||||
AS_CASE(["$target_os"],
|
||||
[emscripten*|wasi*], [
|
||||
|
@ -2933,8 +2931,6 @@ AC_ARG_WITH(mjit-tabs,
|
|||
AC_SUBST(MJIT_TABS)dnl
|
||||
AC_SUBST(DLDFLAGS)dnl
|
||||
AC_SUBST(ARCH_FLAG)dnl
|
||||
AC_SUBST(MJIT_HEADER_FLAGS)dnl
|
||||
AC_SUBST(MJIT_HEADER_INSTALL_DIR)dnl
|
||||
AC_SUBST(MJIT_CC)dnl
|
||||
AS_CASE(["$GCC:$target_os"],
|
||||
[yes:aix*], [mjit_std_cflag="-std=gnu99"],
|
||||
|
@ -3407,12 +3403,6 @@ AS_CASE(["$target_os"],
|
|||
AC_ARG_ENABLE(multiarch,
|
||||
AS_HELP_STRING([--enable-multiarch], [enable multiarch compatible directories]),
|
||||
[multiarch=], [unset multiarch])
|
||||
AS_IF([test ${multiarch+set}], [
|
||||
AC_DEFINE(ENABLE_MULTIARCH)
|
||||
MJIT_HEADER_INSTALL_DIR=include/'${arch}/${RUBY_VERSION_NAME}'
|
||||
], [
|
||||
MJIT_HEADER_INSTALL_DIR=include/'${RUBY_VERSION_NAME}/${arch}'
|
||||
])
|
||||
|
||||
archlibdir='${libdir}/${arch}'
|
||||
sitearchlibdir='${libdir}/${sitearch}'
|
||||
|
|
|
@ -386,34 +386,6 @@ ifneq ($(filter update-bundled_gems refresh-gems,$(MAKECMDGOALS)),)
|
|||
update-gems: update-bundled_gems
|
||||
endif
|
||||
|
||||
ifeq ($(filter 0 1,$(words $(arch_flags))),)
|
||||
$(foreach x,$(patsubst -arch=%,%,$(arch_flags)), \
|
||||
$(eval $$(MJIT_HEADER:.h=)-$(value x).h \
|
||||
$$(MJIT_MIN_HEADER:.h=)-$(value x).h \
|
||||
$$(TIMESTAMPDIR)/$$(MJIT_HEADER:.h=)-$(value x).time \
|
||||
: ARCH_FLAG := -arch $(value x)))
|
||||
|
||||
$(foreach x,$(patsubst -arch=%,%,$(arch_flags)), \
|
||||
$(eval $$(MJIT_HEADER:.h=)-$(value x).h: \
|
||||
$$(TIMESTAMPDIR)/$$(MJIT_HEADER:.h=)-$(value x).time))
|
||||
|
||||
mjit_min_headers := $(patsubst -arch=%,$(MJIT_MIN_HEADER:.h=-%.h),$(arch_flags))
|
||||
$(MJIT_MIN_HEADER): $(mjit_min_headers) $(PREP)
|
||||
@ set -e; set $(patsubst -arch=%,%,$(arch_flags)); \
|
||||
cd $(@D); h=$(@F:.h=); \
|
||||
exec > $(@F).new; \
|
||||
echo '#if 0'; \
|
||||
for arch; do\
|
||||
echo "#elif defined __$${arch}__"; \
|
||||
echo "# include \"$$h-$$arch.h\""; \
|
||||
done; \
|
||||
echo "#else"; echo "# error unsupported platform"; echo "#endif"
|
||||
$(IFCHANGE) $@ $@.new
|
||||
$(Q) $(MAKEDIRS) $(MJIT_HEADER_INSTALL_DIR)
|
||||
$(Q) $(MAKE_LINK) $@ $(MJIT_HEADER_INSTALL_DIR)/$(@F)
|
||||
|
||||
endif
|
||||
|
||||
.SECONDARY: update-unicode-files
|
||||
.SECONDARY: update-unicode-auxiliary-files
|
||||
.SECONDARY: update-unicode-ucd-emoji-files
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
arch_flags := $(filter -arch=%,$(subst -arch ,-arch=,$(ARCH_FLAG)))
|
||||
ifeq ($(filter 0 1,$(words $(arch_flags))),)
|
||||
override MJIT_HEADER_SUFFIX = -%
|
||||
override MJIT_HEADER_ARCH = -$(word 2,$(ARCH_FLAG))
|
||||
endif
|
|
@ -9,10 +9,6 @@
|
|||
|
||||
#include "ruby-runner.h"
|
||||
|
||||
#ifdef MAKE_MJIT_BUILD_DIR
|
||||
const char MJIT_HEADER[] = BUILDDIR "/" MJIT_MIN_HEADER;
|
||||
#else
|
||||
|
||||
static void
|
||||
insert_env_path(const char *envname, const char *paths, size_t size, int prepend)
|
||||
{
|
||||
|
@ -91,5 +87,3 @@ main(int argc, char **argv)
|
|||
perror(rubypath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* MAKE_MJIT_BUILD_DIR */
|
||||
|
|
|
@ -27,7 +27,6 @@ override UNICODE_TABLES_DEPENDENTS = \
|
|||
$(UNICODE_TABLES_DATA_FILES)))),\
|
||||
force,none)
|
||||
|
||||
include $(srcdir)/defs/universal.mk
|
||||
-include uncommon.mk
|
||||
include $(srcdir)/defs/gmake.mk
|
||||
|
||||
|
|
|
@ -96,20 +96,12 @@ USE_RUBYGEMS = @USE_RUBYGEMS@
|
|||
USE_RUBYGEMS_ = $(USE_RUBYGEMS:yes=)
|
||||
CPPFLAGS = @CPPFLAGS@ $(USE_RUBYGEMS_:no=-DDISABLE_RUBYGEMS=1)
|
||||
MJIT_SUPPORT = @MJIT_SUPPORT@
|
||||
MJIT_HEADER_FLAGS = @MJIT_HEADER_FLAGS@
|
||||
MJIT_HEADER_SUFFIX =
|
||||
MJIT_HEADER_ARCH =
|
||||
MJIT_HEADER_INSTALL_DIR = @MJIT_HEADER_INSTALL_DIR@
|
||||
MJIT_CC = @MJIT_CC@
|
||||
MJIT_CFLAGS = @MJIT_CFLAGS@
|
||||
MJIT_OPTFLAGS = @MJIT_OPTFLAGS@
|
||||
MJIT_DEBUGFLAGS = @MJIT_DEBUGFLAGS@
|
||||
MJIT_LDSHARED = @MJIT_LDSHARED@
|
||||
MJIT_DLDFLAGS = $(XDLDFLAGS)
|
||||
MJIT_HEADER = rb_mjit_header.h
|
||||
MJIT_MIN_HEADER_NAME = rb_mjit_min_header-$(RUBY_PROGRAM_VERSION).h
|
||||
MJIT_MIN_HEADER = $(MJIT_HEADER_BUILD_DIR)/$(MJIT_MIN_HEADER_NAME)
|
||||
MJIT_HEADER_BUILD_DIR = $(EXTOUT)/include/$(arch)
|
||||
MJIT_TABS=@MJIT_TABS@
|
||||
YJIT_SUPPORT=@YJIT_SUPPORT@
|
||||
YJIT_LIBS=@YJIT_LIBS@
|
||||
|
@ -183,7 +175,6 @@ MAJOR= @MAJOR@
|
|||
MINOR= @MINOR@
|
||||
TEENY= @TEENY@
|
||||
|
||||
# here for MJIT_MIN_HEADER_NAME, not in common.mk
|
||||
RUBY_PROGRAM_VERSION = $(MAJOR).$(MINOR).$(TEENY)
|
||||
|
||||
LIBRUBY_A = @LIBRUBY_A@
|
||||
|
@ -490,17 +481,8 @@ probes.$(OBJEXT): $(srcdir)/probes.d $(DTRACE_REBUILD:yes=probes.stamp)
|
|||
$(Q) $(RM) $@
|
||||
$(Q) $(DTRACE) -G -C $(INCFLAGS) -s $(srcdir)/probes.d -o $@ $(DTRACE_REBUILD_OBJS)
|
||||
|
||||
main: mjit-headers
|
||||
yes-mjit-headers: $(MJIT_MIN_HEADER)
|
||||
clean-local::
|
||||
$(Q)$(RM) \
|
||||
$(MJIT_HEADER) $(MJIT_HEADER:.h=)$(MJIT_HEADER_SUFFIX:%=*).h \
|
||||
$(MJIT_MIN_HEADER) $(MJIT_MIN_HEADER:.h=)$(MJIT_HEADER_SUFFIX:%=*).h \
|
||||
$(MJIT_HEADER_INSTALL_DIR)/rb_mjit_min_header-*.h \
|
||||
$(TIMESTAMPDIR)/$(MJIT_HEADER:.h=)$(MJIT_HEADER_SUFFIX).time mjit_config.h \
|
||||
|| $(NULLCMD)
|
||||
$(Q)$(RM) -r mjit_build_dir.*
|
||||
-$(Q) $(RMDIRS) $(MJIT_HEADER_INSTALL_DIR) $(MJIT_HEADER_BUILD_DIR) $(TIMESTAMPDIR) 2> $(NULL) || $(NULLCMD)
|
||||
|
||||
# DTrace static library hacks described here:
|
||||
# https://marc.info/?l=opensolaris-dtrace-discuss&m=114761203110734&w=4
|
||||
|
@ -669,12 +651,6 @@ mjit_config.h:
|
|||
echo '#define RUBY_MJIT_CONFIG_H 1'; \
|
||||
echo; \
|
||||
sep=; \
|
||||
echo '#ifdef LOAD_RELATIVE'; \
|
||||
quote MJIT_HEADER_INSTALL_DIR "/$(MJIT_HEADER_INSTALL_DIR)"; \
|
||||
echo '#else'; \
|
||||
quote MJIT_HEADER_INSTALL_DIR "$(rubyarchhdrdir)"; \
|
||||
echo '#endif'; \
|
||||
quote MJIT_MIN_HEADER_NAME "$(MJIT_MIN_HEADER_NAME)"; \
|
||||
sep=,; \
|
||||
quote "MJIT_CC_COMMON " $(MJIT_CC); \
|
||||
quote "MJIT_CFLAGS MJIT_ARCHFLAG" $(MJIT_CFLAGS); \
|
||||
|
@ -691,10 +667,10 @@ mjit_config.h:
|
|||
} > $@
|
||||
|
||||
yes-test-almost yes-test-all programs: mjit_build_dir.$(SOEXT)
|
||||
mjit_build_dir.$(SOEXT): $(MJIT_MIN_HEADER) $(srcdir)/ruby-runner.c ruby-runner.h
|
||||
mjit_build_dir.$(SOEXT): $(srcdir)/ruby-runner.c ruby-runner.h
|
||||
$(ECHO) making $@
|
||||
$(Q) $(DLDSHARED) $(MJIT_DLDFLAGS) $(ARCH_FLAG) $(CFLAGS) $(INCFLAGS) $(CPPFLAGS) \
|
||||
-DMAKE_MJIT_BUILD_DIR=1 -DMJIT_MIN_HEADER='"$(MJIT_MIN_HEADER)"' \
|
||||
-DMAKE_MJIT_BUILD_DIR=1 \
|
||||
$(OUTFLAG)$@ $(srcdir)/ruby-runner.c
|
||||
|
||||
# yes-test-basic: leaked-globals
|
||||
|
|
|
@ -1,319 +0,0 @@
|
|||
# Copyright (C) 2017 Vladimir Makarov, <vmakarov@redhat.com>
|
||||
# This is a script to transform functions to static inline.
|
||||
# Usage: transform_mjit_header.rb <c-compiler> <header file> <out>
|
||||
|
||||
require 'fileutils'
|
||||
require 'tempfile'
|
||||
|
||||
PROGRAM = File.basename($0, ".*")
|
||||
|
||||
module MJITHeader
|
||||
ATTR_VALUE_REGEXP = /[^()]|\([^()]*\)/
|
||||
ATTR_REGEXP = /__attribute__\s*\(\(#{ATTR_VALUE_REGEXP}*\)\)/
|
||||
# Example:
|
||||
# VALUE foo(int bar)
|
||||
# VALUE __attribute__ ((foo)) bar(int baz)
|
||||
# __attribute__ ((foo)) VALUE bar(int baz)
|
||||
FUNC_HEADER_REGEXP = /\A[^\[{(]*(\s*#{ATTR_REGEXP})*[^\[{(]*\((#{ATTR_REGEXP}|[^()])*\)(\s*#{ATTR_REGEXP})*\s*/
|
||||
TARGET_NAME_REGEXP = /\A(rb|ruby|vm|insn|attr|Init)_/
|
||||
|
||||
# Predefined macros for compilers which are already supported by MJIT.
|
||||
# We're going to support cl.exe too (WIP) but `cl.exe -E` can't produce macro.
|
||||
SUPPORTED_CC_MACROS = [
|
||||
'__GNUC__', # gcc
|
||||
'__clang__', # clang
|
||||
]
|
||||
|
||||
# These macros are relied on this script's transformation
|
||||
PREFIXED_MACROS = [
|
||||
'ALWAYS_INLINE',
|
||||
'COLDFUNC',
|
||||
'inline',
|
||||
'RBIMPL_ATTR_COLD',
|
||||
]
|
||||
|
||||
# For MinGW's ras.h. Those macros have its name in its definition and can't be preprocessed multiple times.
|
||||
RECURSIVE_MACROS = %w[
|
||||
RASCTRYINFO
|
||||
RASIPADDR
|
||||
]
|
||||
|
||||
IGNORED_FUNCTIONS = [
|
||||
'rb_vm_search_method_slowpath', # This increases the time to compile when inlined. So we use it as external function.
|
||||
'rb_equal_opt', # Not used from VM and not compilable
|
||||
'ruby_abi_version',
|
||||
]
|
||||
|
||||
ALWAYS_INLINED_FUNCTIONS = [
|
||||
'vm_opt_plus',
|
||||
'vm_opt_minus',
|
||||
'vm_opt_mult',
|
||||
'vm_opt_div',
|
||||
'vm_opt_mod',
|
||||
'vm_opt_neq',
|
||||
'vm_opt_lt',
|
||||
'vm_opt_le',
|
||||
'vm_opt_gt',
|
||||
'vm_opt_ge',
|
||||
'vm_opt_ltlt',
|
||||
'vm_opt_and',
|
||||
'vm_opt_or',
|
||||
'vm_opt_aref',
|
||||
'vm_opt_aset',
|
||||
'vm_opt_aref_with',
|
||||
'vm_opt_aset_with',
|
||||
'vm_opt_not',
|
||||
]
|
||||
|
||||
COLD_FUNCTIONS = %w[
|
||||
setup_parameters_complex
|
||||
vm_call_iseq_setup
|
||||
vm_call_iseq_setup_2
|
||||
vm_call_iseq_setup_tailcall
|
||||
vm_call_method_each_type
|
||||
vm_ic_update
|
||||
]
|
||||
|
||||
# Return start..stop of last decl in CODE ending STOP
|
||||
def self.find_decl(code, stop)
|
||||
level = 0
|
||||
i = stop
|
||||
while i = code.rindex(/[;{}]/, i)
|
||||
if level == 0 && stop != i && decl_found?($&, i)
|
||||
return decl_start($&, i)..stop
|
||||
end
|
||||
case $&
|
||||
when '}'
|
||||
level += 1
|
||||
when '{'
|
||||
level -= 1
|
||||
end
|
||||
i -= 1
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
def self.decl_found?(code, i)
|
||||
i == 0 || code == ';' || code == '}'
|
||||
end
|
||||
|
||||
def self.decl_start(code, i)
|
||||
if i == 0 && code != ';' && code != '}'
|
||||
0
|
||||
else
|
||||
i + 1
|
||||
end
|
||||
end
|
||||
|
||||
# Given DECL return the name of it, nil if failed
|
||||
def self.decl_name_of(decl)
|
||||
ident_regex = /\w+/
|
||||
decl = decl.gsub(/^#.+$/, '') # remove macros
|
||||
reduced_decl = decl.gsub(ATTR_REGEXP, '') # remove attributes
|
||||
su1_regex = /{[^{}]*}/
|
||||
su2_regex = /{([^{}]|#{su1_regex})*}/
|
||||
su3_regex = /{([^{}]|#{su2_regex})*}/ # 3 nested structs/unions is probably enough
|
||||
reduced_decl.gsub!(su3_regex, '') # remove structs/unions in the header
|
||||
id_seq_regex = /\s*(?:#{ident_regex}(?:\s+|\s*[*]+\s*))*/
|
||||
# Process function header:
|
||||
match = /\A#{id_seq_regex}(?<name>#{ident_regex})\s*\(/.match(reduced_decl)
|
||||
return match[:name] if match
|
||||
# Process non-function declaration:
|
||||
reduced_decl.gsub!(/\s*=[^;]+(?=;)/, '') # remove initialization
|
||||
match = /#{id_seq_regex}(?<name>#{ident_regex})/.match(reduced_decl);
|
||||
return match[:name] if match
|
||||
nil
|
||||
end
|
||||
|
||||
# Return true if CC with CFLAGS compiles successfully the current code.
|
||||
# Use STAGE in the message in case of a compilation failure
|
||||
def self.check_code!(code, cc, cflags, stage)
|
||||
with_code(code) do |path|
|
||||
cmd = "#{cc} #{cflags} #{path}"
|
||||
out = IO.popen(cmd, err: [:child, :out], &:read)
|
||||
unless $?.success?
|
||||
STDERR.puts "error in #{stage} header file:\n#{out}"
|
||||
exit false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Remove unpreprocessable macros
|
||||
def self.remove_harmful_macros!(code)
|
||||
code.gsub!(/^#define #{Regexp.union(RECURSIVE_MACROS)} .*$/, '')
|
||||
end
|
||||
|
||||
# -dD outputs those macros, and it produces redefinition warnings or errors
|
||||
# This assumes common.mk passes `-DMJIT_HEADER` first when it creates rb_mjit_header.h.
|
||||
def self.remove_predefined_macros!(code)
|
||||
code.sub!(/\A(#define [^\n]+|\n)*(#define MJIT_HEADER 1\n)/, '\2')
|
||||
end
|
||||
|
||||
# Return [macro, others]. But others include PREFIXED_MACROS to be used in code.
|
||||
def self.separate_macro_and_code(code)
|
||||
code.lines.partition do |l|
|
||||
l.start_with?('#') && PREFIXED_MACROS.all? { |m| !l.start_with?("#define #{m}") }
|
||||
end.map! { |lines| lines.join('') }
|
||||
end
|
||||
|
||||
def self.write(code, out)
|
||||
# create with strict permission, then will install proper
|
||||
# permission
|
||||
FileUtils.mkdir_p(File.dirname(out), mode: 0700)
|
||||
File.binwrite("#{out}.new", code, perm: 0600)
|
||||
FileUtils.mv("#{out}.new", out)
|
||||
end
|
||||
|
||||
# Note that this checks runruby. This conservatively covers platform names.
|
||||
def self.windows?
|
||||
RUBY_PLATFORM =~ /mswin|mingw|msys/
|
||||
end
|
||||
|
||||
# If code has macro which only supported compilers predefine, return true.
|
||||
def self.supported_header?(code)
|
||||
SUPPORTED_CC_MACROS.any? { |macro| code =~ /^#\s*define\s+#{Regexp.escape(macro)}\b/ }
|
||||
end
|
||||
|
||||
# This checks if syntax check outputs one of the following messages.
|
||||
# "error: conflicting types for 'restrict'"
|
||||
# "error: redefinition of parameter 'restrict'"
|
||||
# If it's true, this script regards platform as AIX or Solaris and adds -std=c99 as workaround.
|
||||
def self.conflicting_types?(code, cc, cflags)
|
||||
with_code(code) do |path|
|
||||
cmd = "#{cc} #{cflags} #{path}"
|
||||
out = IO.popen(cmd, err: [:child, :out], &:read)
|
||||
!$?.success? &&
|
||||
(out.match?(/error: conflicting types for '[^']+'/) ||
|
||||
out.match?(/error: redefinition of parameter '[^']+'/))
|
||||
end
|
||||
end
|
||||
|
||||
def self.with_code(code)
|
||||
# for `system_header` pragma which can't be in the main file.
|
||||
Tempfile.open(['', '.h'], mode: File::BINARY) do |f|
|
||||
f.puts code
|
||||
f.close
|
||||
Tempfile.open(['', '.c'], mode: File::BINARY) do |c|
|
||||
c.puts <<SRC
|
||||
#include "#{f.path}"
|
||||
SRC
|
||||
c.close
|
||||
return yield(c.path)
|
||||
end
|
||||
end
|
||||
end
|
||||
private_class_method :with_code
|
||||
end
|
||||
|
||||
if ARGV.size != 3
|
||||
abort "Usage: #{$0} <c-compiler> <header file> <out>"
|
||||
end
|
||||
|
||||
if STDOUT.tty?
|
||||
require_relative 'lib/colorize'
|
||||
color = Colorize.new
|
||||
end
|
||||
cc = ARGV[0]
|
||||
code = File.binread(ARGV[1]) # Current version of the header file.
|
||||
outfile = ARGV[2]
|
||||
cflags = '-S -DMJIT_HEADER -fsyntax-only -Werror=implicit-function-declaration -Werror=implicit-int -Wfatal-errors'
|
||||
|
||||
if !MJITHeader.supported_header?(code)
|
||||
puts "This compiler (#{cc}) looks not supported for MJIT. Giving up to generate MJIT header."
|
||||
MJITHeader.write("#error MJIT does not support '#{cc}' yet", outfile)
|
||||
exit
|
||||
end
|
||||
|
||||
MJITHeader.remove_predefined_macros!(code)
|
||||
|
||||
if MJITHeader.windows? # transformation is broken on Windows and the platform is not supported
|
||||
MJITHeader.remove_harmful_macros!(code)
|
||||
MJITHeader.check_code!(code, cc, cflags, 'initial')
|
||||
puts "\nSkipped transforming external functions to static on Windows."
|
||||
MJITHeader.write(code, outfile)
|
||||
exit
|
||||
end
|
||||
|
||||
macro, code = MJITHeader.separate_macro_and_code(code) # note: this does not work on MinGW
|
||||
code = <<header + code
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
header
|
||||
code_to_check = "#{code}#{macro}" # macro should not affect code again
|
||||
|
||||
if MJITHeader.conflicting_types?(code_to_check, cc, cflags)
|
||||
cflags = "#{cflags} -std=c99" # For AIX gcc
|
||||
end
|
||||
|
||||
# Check initial file correctness in the manner of final output.
|
||||
MJITHeader.check_code!(code_to_check, cc, cflags, 'initial')
|
||||
|
||||
stop_pos = -1
|
||||
extern_names = []
|
||||
transform_logs = Hash.new { |h, k| h[k] = [] }
|
||||
|
||||
# This loop changes function declarations to static inline.
|
||||
while (decl_range = MJITHeader.find_decl(code, stop_pos))
|
||||
stop_pos = decl_range.begin - 1
|
||||
decl = code[decl_range]
|
||||
decl_name = MJITHeader.decl_name_of(decl)
|
||||
|
||||
if MJITHeader::IGNORED_FUNCTIONS.include?(decl_name) && /#{MJITHeader::FUNC_HEADER_REGEXP}{/.match(decl)
|
||||
transform_logs[:def_to_decl] << decl_name
|
||||
code[decl_range] = decl.sub(/{.+}/m, ';')
|
||||
elsif MJITHeader::COLD_FUNCTIONS.include?(decl_name) && match = /#{MJITHeader::FUNC_HEADER_REGEXP}{/.match(decl)
|
||||
header = match[0].sub(/{\z/, '').strip
|
||||
header = "static #{header.sub(/\A((static|inline) )+/, '')}"
|
||||
decl[match.begin(0)...match.end(0)] = '{' # remove header
|
||||
code[decl_range] = "\nCOLDFUNC #{header} #{decl}"
|
||||
elsif MJITHeader::ALWAYS_INLINED_FUNCTIONS.include?(decl_name) && match = /#{MJITHeader::FUNC_HEADER_REGEXP}{/.match(decl)
|
||||
header = match[0].sub(/{\z/, '').strip
|
||||
header = "static inline #{header.sub(/\A((static|inline) )+/, '')}"
|
||||
decl[match.begin(0)...match.end(0)] = '{' # remove header
|
||||
code[decl_range] = "\nALWAYS_INLINE(#{header});\n#{header} #{decl}"
|
||||
elsif extern_names.include?(decl_name) && (decl =~ /#{MJITHeader::FUNC_HEADER_REGEXP};/)
|
||||
decl.sub!(/(extern|static|inline) /, ' ')
|
||||
unless decl_name =~ /\Aattr_\w+_\w+\z/ # skip too-many false-positive warnings in insns_info.inc.
|
||||
transform_logs[:static_inline_decl] << decl_name
|
||||
end
|
||||
|
||||
code[decl_range] = "static inline #{decl}"
|
||||
elsif (match = /#{MJITHeader::FUNC_HEADER_REGEXP}{/.match(decl)) && (header = match[0]) !~ /static/
|
||||
unless decl_name.match(MJITHeader::TARGET_NAME_REGEXP)
|
||||
transform_logs[:skipped] << decl_name
|
||||
next
|
||||
end
|
||||
|
||||
extern_names << decl_name
|
||||
decl[match.begin(0)...match.end(0)] = ''
|
||||
|
||||
if decl =~ /\bstatic\b/
|
||||
abort "#{PROGRAM}: a static decl was found inside external definition #{decl_name.dump}"
|
||||
end
|
||||
|
||||
header.sub!(/(extern|inline) /, ' ')
|
||||
unless decl_name =~ /\Aattr_\w+_\w+\z/ # skip too-many false-positive warnings in insns_info.inc.
|
||||
transform_logs[:static_inline_def] << decl_name
|
||||
end
|
||||
code[decl_range] = "static inline #{header}#{decl}"
|
||||
end
|
||||
end
|
||||
|
||||
code << macro
|
||||
|
||||
# Check the final file correctness
|
||||
MJITHeader.check_code!(code, cc, cflags, 'final')
|
||||
|
||||
MJITHeader.write(code, outfile)
|
||||
|
||||
messages = {
|
||||
def_to_decl: 'changing definition to declaration',
|
||||
static_inline_def: 'making external definition static inline',
|
||||
static_inline_decl: 'making declaration static inline',
|
||||
skipped: 'SKIPPED to transform',
|
||||
}
|
||||
transform_logs.each do |key, decl_names|
|
||||
decl_names = decl_names.map { |s| color.bold(s) } if color
|
||||
puts("#{PROGRAM}: #{messages.fetch(key)}: #{decl_names.join(', ')}")
|
||||
end
|
Загрузка…
Ссылка в новой задаче