ruby-changes:52081
From: k0kubun <ko1@a...>
Date: Sat, 11 Aug 2018 18:37:19 +0900 (JST)
Subject: [ruby-changes:52081] k0kubun:r64289 (trunk): mjit.c: include mjit_worker.c
k0kubun 2018-08-11 18:37:14 +0900 (Sat, 11 Aug 2018) New Revision: 64289 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=64289 Log: mjit.c: include mjit_worker.c instead of linking functions with mjit_worker.o. In the r64285's structure, we needed to publish some variables with mjit_ prefix. But ideally those variables should be completely private in mjit.o (or old mjit_worker.o), and it was hard. So I chose an approach similar to vm*.c for mjit.c and mjit_worker.c. I believe mjit_compile.c is still nice to be separated. After this commit, I'll remove the mjit_ prefix again... Removed files: trunk/mjit_internal.h Modified files: trunk/common.mk trunk/mjit.c trunk/mjit_worker.c Index: mjit_internal.h =================================================================== --- mjit_internal.h (revision 64288) +++ mjit_internal.h (nonexistent) @@ -1,256 +0,0 @@ https://github.com/ruby/ruby/blob/trunk/mjit_internal.h#L0 -/********************************************************************** - - mjit_internal.h - Utility functions shared by mjit*.c - - Copyright (C) 2018 Takashi Kokubun <takashikkbn@g...>. - -**********************************************************************/ - -/* NOTE: All functions in this file can be executed on MJIT worker. So don't - call Ruby methods (C functions that may call rb_funcall) or trigger - GC (using xmalloc, ZALLOC, etc.) in this file. */ - -#ifndef RUBY_MJIT_INTERNAL_H -#define RUBY_MJIT_INTERNAL_H 1 - -#include "mjit.h" - -#ifndef MAXPATHLEN -# define MAXPATHLEN 1024 -#endif - -#ifdef _WIN32 -#define dlopen(name,flag) ((void*)LoadLibrary(name)) -#define dlerror() strerror(rb_w32_map_errno(GetLastError())) -#define dlsym(handle,name) ((void*)GetProcAddress((handle),(name))) -#define dlclose(handle) (FreeLibrary(handle)) -#define RTLD_NOW -1 -#endif - -#define MJIT_TMP_PREFIX "_ruby_mjit_" - -/* The unit structure that holds metadata of ISeq for MJIT. */ -struct rb_mjit_unit { - /* Unique order number of unit. */ - int id; - /* Dlopen handle of the loaded object file. */ - void *handle; - const rb_iseq_t *iseq; -#ifndef _MSC_VER - /* This value is always set for `compact_all_jit_code`. Also used for lazy deletion. */ - char *o_file; -#endif -#ifdef _WIN32 - /* DLL cannot be removed while loaded on Windows. If this is set, it'll be lazily deleted. */ - char *so_file; -#endif - /* Only used by unload_units. Flag to check this unit is currently on stack or not. */ - char used_code_p; -}; - -/* Node of linked list in struct rb_mjit_unit_list. - TODO: use ccan/list for this */ -struct rb_mjit_unit_node { - struct rb_mjit_unit *unit; - struct rb_mjit_unit_node *next, *prev; -}; - -/* Linked list of struct rb_mjit_unit. */ -struct rb_mjit_unit_list { - struct rb_mjit_unit_node *head; - int length; /* the list length */ -}; - -enum pch_status_t {PCH_NOT_READY, PCH_FAILED, PCH_SUCCESS}; - -extern void rb_native_mutex_lock(rb_nativethread_lock_t *lock); -extern void rb_native_mutex_unlock(rb_nativethread_lock_t *lock); -extern void rb_native_mutex_initialize(rb_nativethread_lock_t *lock); -extern void rb_native_mutex_destroy(rb_nativethread_lock_t *lock); - -extern void rb_native_cond_initialize(rb_nativethread_cond_t *cond); -extern void rb_native_cond_destroy(rb_nativethread_cond_t *cond); -extern void rb_native_cond_signal(rb_nativethread_cond_t *cond); -extern void rb_native_cond_broadcast(rb_nativethread_cond_t *cond); -extern void rb_native_cond_wait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex); - -extern char *mjit_tmp_dir; - -static int -sprint_uniq_filename(char *str, size_t size, unsigned long id, const char *prefix, const char *suffix) -{ - return snprintf(str, size, "%s/%sp%"PRI_PIDT_PREFIX"uu%lu%s", mjit_tmp_dir, prefix, getpid(), id, suffix); -} - -/* Print the arguments according to FORMAT to stderr only if MJIT - verbose option value is more or equal to LEVEL. */ -PRINTF_ARGS(static void, 2, 3) -verbose(int level, const char *format, ...) -{ - va_list args; - - va_start(args, format); - if (mjit_opts.verbose >= level) - vfprintf(stderr, format, args); - va_end(args); - if (mjit_opts.verbose >= level) - fprintf(stderr, "\n"); -} - -extern rb_nativethread_lock_t mjit_engine_mutex; - -/* Start a critical section. Use message MSG to print debug info at - LEVEL. */ -static inline void -CRITICAL_SECTION_START(int level, const char *msg) -{ - verbose(level, "Locking %s", msg); - rb_native_mutex_lock(&mjit_engine_mutex); - verbose(level, "Locked %s", msg); -} - -/* Finish the current critical section. Use message MSG to print - debug info at LEVEL. */ -static inline void -CRITICAL_SECTION_FINISH(int level, const char *msg) -{ - verbose(level, "Unlocked %s", msg); - rb_native_mutex_unlock(&mjit_engine_mutex); -} - -/* Allocate struct rb_mjit_unit_node and return it. This MUST NOT be - called inside critical section because that causes deadlock. ZALLOC - may fire GC and GC hooks mjit_gc_start_hook that starts critical section. */ -static struct rb_mjit_unit_node * -create_list_node(struct rb_mjit_unit *unit) -{ - struct rb_mjit_unit_node *node = ZALLOC(struct rb_mjit_unit_node); - node->unit = unit; - return node; -} - -/* Add unit node to the tail of doubly linked LIST. It should be not in - the list before. */ -static void -add_to_list(struct rb_mjit_unit_node *node, struct rb_mjit_unit_list *list) -{ - /* Append iseq to list */ - if (list->head == NULL) { - list->head = node; - } - else { - struct rb_mjit_unit_node *tail = list->head; - while (tail->next != NULL) { - tail = tail->next; - } - tail->next = node; - node->prev = tail; - } - list->length++; -} - -static void -remove_from_list(struct rb_mjit_unit_node *node, struct rb_mjit_unit_list *list) -{ - if (node->prev && node->next) { - node->prev->next = node->next; - node->next->prev = node->prev; - } - else if (node->prev == NULL && node->next) { - list->head = node->next; - node->next->prev = NULL; - } - else if (node->prev && node->next == NULL) { - node->prev->next = NULL; - } - else { - list->head = NULL; - } - list->length--; - xfree(node); -} - -static void -remove_file(const char *filename) -{ - if (remove(filename) && (mjit_opts.warnings || mjit_opts.verbose)) { - fprintf(stderr, "MJIT warning: failed to remove \"%s\": %s\n", - filename, strerror(errno)); - } -} - -/* Lazily delete .o and/or .so files. */ -static void -clean_object_files(struct rb_mjit_unit *unit) -{ -#ifndef _MSC_VER - if (unit->o_file) { - char *o_file = unit->o_file; - - unit->o_file = NULL; - /* For compaction, unit->o_file is always set when compilation succeeds. - So save_temps needs to be checked here. */ - if (!mjit_opts.save_temps) - remove_file(o_file); - free(o_file); - } -#endif - -#ifdef _WIN32 - if (unit->so_file) { - char *so_file = unit->so_file; - - unit->so_file = NULL; - /* unit->so_file is set only when mjit_opts.save_temps is FALSE. */ - remove_file(so_file); - free(so_file); - } -#endif -} - -/* This is called in the following situations: - 1) On dequeue or `unload_units()`, associated ISeq is already GCed. - 2) The unit is not called often and unloaded by `unload_units()`. - 3) Freeing lists on `mjit_finish()`. - - `jit_func` value does not matter for 1 and 3 since the unit won't be used anymore. - For the situation 2, this sets the ISeq's JIT state to NOT_COMPILED_JIT_ISEQ_FUNC - to prevent the situation that the same methods are continously compiled. */ -static void -free_unit(struct rb_mjit_unit *unit) -{ - if (unit->iseq) { /* ISeq is not GCed */ - unit->iseq->body->jit_func = (mjit_func_t)NOT_COMPILED_JIT_ISEQ_FUNC; - unit->iseq->body->jit_unit = NULL; - } - if (unit->handle) /* handle is NULL if it's in queue */ - dlclose(unit->handle); - clean_object_files(unit); - xfree(unit); -} - -#define append_str2(p, str, len) ((char *)memcpy((p), str, (len))+(len)) -#define append_str(p, str) append_str2(p, str, sizeof(str)-1) -#define append_lit(p, str) append_str2(p, str, rb_strlen_lit(str)) - -#include "mjit_config.h" - -#if defined(__GNUC__) && \ - (!defined(__clang__) || \ - (defined(__clang__) && (defined(__FreeBSD__) || defined(__GLIBC__)))) -#define GCC_PIC_FLAGS "-Wfatal-errors", "-fPIC", "-shared", "-w", \ - "-pipe", -#else -#define GCC_PIC_FLAGS /* empty */ -#endif - -static const char *const CC_COMMON_ARGS[] = { - MJIT_CC_COMMON MJIT_CFLAGS GCC_PIC_FLAGS - NULL -}; - -/* GCC and CLANG executable paths. TODO: The paths should absolute - ones to prevent changing C compiler for security reasons. */ -#define CC_PATH CC_COMMON_ARGS[0] - -#endif /* RUBY_MJIT_INTERNAL_H */ Property changes on: mjit_internal.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -LF \ No newline at end of property Index: common.mk =================================================================== --- common.mk (revision 64288) +++ common.mk (revision 64289) @@ -100,7 +100,6 @@ COMMONOBJS = array.$(OBJEXT) \ https://github.com/ruby/ruby/blob/trunk/common.mk#L100 math.$(OBJEXT) \ mjit.$(OBJEXT) \ mjit_compile.$(OBJEXT) \ - mjit_worker.$(OBJEXT) \ node.$(OBJEXT) \ numeric.$(OBJEXT) \ object.$(OBJEXT) \ @@ -2216,7 +2215,7 @@ mjit.$(OBJEXT): {$(VPATH)}missing.h https://github.com/ruby/ruby/blob/trunk/common.mk#L2215 mjit.$(OBJEXT): {$(VPATH)}mjit.c mjit.$(OBJEXT): {$(VPATH)}mjit.h mjit.$(OBJEXT): {$(VPATH)}mjit_config.h -mjit.$(OBJEXT): {$(VPATH)}mjit_internal.h +mjit.$(OBJEXT): {$(VPATH)}mjit_worker.c mjit.$(OBJEXT): {$(VPATH)}node.h mjit.$(OBJEXT): {$(VPATH)}ruby_assert.h mjit.$(OBJEXT): {$(VPATH)}ruby_atomic.h @@ -2258,9 +2257,6 @@ mjit_compile.$(OBJEXT): {$(VPATH)}vm_cor https://github.com/ruby/ruby/blob/trunk/common.mk#L2257 mjit_compile.$(OBJEXT): {$(VPATH)}vm_exec.h mjit_compile.$(OBJEXT): {$(VPATH)}vm_insnhelper.h mjit_compile.$(OBJEXT): {$(VPATH)}vm_opts.h -mjit_worker.$(OBJEXT): {$(VPATH)}mjit.h -mjit_worker.$(OBJEXT): {$(VPATH)}mjit_internal.h -mjit_worker.$(OBJEXT): {$(VPATH)}mjit_worker.c node.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h node.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h node.$(OBJEXT): $(CCAN_DIR)/list/list.h Index: mjit_worker.c =================================================================== --- mjit_worker.c (revision 64288) +++ mjit_worker.c (revision 64289) @@ -97,7 +97,244 @@ https://github.com/ruby/ruby/blob/trunk/mjit_worker.c#L97 #endif #include "dln.h" -#include "mjit_internal.h" + +#ifndef MAXPATHLEN +# define MAXPATHLEN 1024 +#endif + +#ifdef _WIN32 +#define dlopen(name,flag) ((void*)LoadLibrary(name)) +#define dlerror() strerror(rb_w32_map_errno(GetLastError())) +#define dlsym(handle,name) ((void*)GetProcAddress((handle),(name))) +#define dlclose(handle) (FreeLibrary(handle)) +#define RTLD_NOW -1 +#endif + +#define MJIT_TMP_PREFIX "_ruby_mjit_" + +/* The unit structure that holds metadata of ISeq for MJIT. */ +struct rb_mjit_unit { + /* Unique order number of unit. */ + int id; + /* Dlopen handle of the loaded object file. */ + void *handle; + const rb_iseq_t *iseq; +#ifndef _MSC_VER + /* This value is always set for `compact_all_jit_code`. Also used for lazy deletion. */ + char *o_file; +#endif +#ifdef _WIN32 + /* DLL cannot be removed while loaded on Windows. If this is set, it'll be lazily deleted. */ + char *so_file; +#endif + /* Only used by unload_units. Flag to check this unit is currently on stack or not. */ + char used_code_p; +}; + +/* Node of linked list in struct rb_mjit_unit_list. + TODO: use ccan/list for this */ +struct rb_mjit_unit_node { + struct rb_mjit_unit *unit; + struct rb_mjit_unit_node *next, *prev; +}; + +/* Linked list of struct rb_mjit_unit. */ +struct rb_mjit_unit_list { + struct rb_mjit_unit_node *head; + int length; /* the list length */ +}; + +enum pch_status_t {PCH_NOT_READY, PCH_FAILED, PCH_SUCCESS}; + +extern void rb_native_mutex_lock(rb_nativethread_lock_t *lock); +extern void rb_native_mutex_unlock(rb_nativethread_lock_t *lock); +extern void rb_native_mutex_initialize(rb_nativethread_lock_t *lock); +extern void rb_native_mutex_destroy(rb_nativethread_lock_t *lock); + +extern void rb_native_cond_initialize(rb_nativethread_cond_t *cond); +extern void rb_native_cond_destroy(rb_nativethread_cond_t *cond); +extern void rb_native_cond_signal(rb_nativethread_cond_t *cond); +extern void rb_native_cond_broadcast(rb_nativethread_cond_t *cond); +extern void rb_native_cond_wait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex); + +extern char *mjit_tmp_dir; + +static int +sprint_uniq_filename(char *str, size_t size, unsigned long id, const char *prefix, const char *suffix) +{ + return snprintf(str, size, "%s/%sp%"PRI_PIDT_PREFIX"uu%lu%s", mjit_tmp_dir, prefix, getpid(), id, suffix); +} + +/* Print the arguments according to FORMAT to stderr only if MJIT + verbose option value is more or equal to LEVEL. */ +PRINTF_ARGS(static void, 2, 3) +verbose(int level, const char *format, ...) +{ + va_list args; + + va_start(args, format); + if (mjit_opts.verbose >= level) + vfprintf(stderr, format, args); + va_end(args); + if (mjit_opts.verbose >= level) + fprintf(stderr, "\n"); +} + +extern rb_nativethread_lock_t mjit_engine_mutex; + +/* Start a critical section. Use message MSG to print debug info at + LEVEL. */ +static inline void +CRITICAL_SECTION_START(int level, const char *msg) +{ + verbose(level, "Locking %s", msg); + rb_native_mutex_lock(&mjit_engine_mutex); + verbose(level, "Locked %s", msg); +} + +/* Finish the current critical section. Use message MSG to print + debug info at LEVEL. */ +static inline void +CRITICAL_SECTION_FINISH(int level, const char *msg) +{ + verbose(level, "Unlocked %s", msg); + rb_native_mutex_unlock(&mjit_engine_mutex); +} + +/* Allocate struct rb_mjit_unit_node and return it. This MUST NOT be + called inside critical section because that causes deadlock. ZALLOC + may fire GC and GC hooks mjit_gc_start_hook that starts critical section. */ +static struct rb_mjit_unit_node * +create_list_node(struct rb_mjit_unit *unit) +{ + struct rb_mjit_unit_node *node = ZALLOC(struct rb_mjit_unit_node); + node->unit = unit; + return node; +} + +/* Add unit node to the tail of doubly linked LIST. It should be not in + the list before. */ +static void +add_to_list(struct rb_mjit_unit_node *node, struct rb_mjit_unit_list *list) +{ + /* Append iseq to list */ + if (list->head == NULL) { + list->head = node; + } + else { + struct rb_mjit_unit_node *tail = list->head; + while (tail->next != NULL) { + tail = tail->next; + } + tail->next = node; + node->prev = tail; + } + list->length++; +} + +static void +remove_from_list(struct rb_mjit_unit_node *node, struct rb_mjit_unit_list *list) +{ + if (node->prev && node->next) { + node->prev->next = node->next; + node->next->prev = node->prev; + } + else if (node->prev == NULL && node->next) { + list->head = node->next; + node->next->prev = NULL; + } + else if (node->prev && node->next == NULL) { + node->prev->next = NULL; + } + else { + list->head = NULL; + } + list->length--; + xfree(node); +} + +static void +remove_file(const char *filename) +{ + if (remove(filename) && (mjit_opts.warnings || mjit_opts.verbose)) { + fprintf(stderr, "MJIT warning: failed to remove \"%s\": %s\n", + filename, strerror(errno)); + } +} + +/* Lazily delete .o and/or .so files. */ +static void +clean_object_files(struct rb_mjit_unit *unit) +{ +#ifndef _MSC_VER + if (unit->o_file) { + char *o_file = unit->o_file; + + unit->o_file = NULL; + /* For compaction, unit->o_file is always set when compilation succeeds. + So save_temps needs to be checked here. */ + if (!mjit_opts.save_temps) + remove_file(o_file); + free(o_file); + } +#endif + +#ifdef _WIN32 + if (unit->so_file) { + char *so_file = unit->so_file; + + unit->so_file = NULL; + /* unit->so_file is set only when mjit_opts.save_temps is FALSE. */ + remove_file(so_file); + free(so_file); + } +#endif +} + +/* This is called in the following situations: + 1) On dequeue or `unload_units()`, associated ISeq is already GCed. + 2) The unit is not called often and unloaded by `unload_units()`. + 3) Freeing lists on `mjit_finish()`. + + `jit_func` value does not matter for 1 and 3 since the unit won't be used anymore. + For the situation 2, this sets the ISeq's JIT state to NOT_COMPILED_JIT_ISEQ_FUNC + to prevent the situation that the same methods are continously compiled. */ +static void +free_unit(struct rb_mjit_unit *unit) +{ + if (unit->iseq) { /* ISeq is not GCed */ + unit->iseq->body->jit_func = (mjit_func_t)NOT_COMPILED_JIT_ISEQ_FUNC; + unit->iseq->body->jit_unit = NULL; + } + if (unit->handle) /* handle is NULL if it's in queue */ + dlclose(unit->handle); + clean_object_files(unit); + xfree(unit); +} + +#define append_str2(p, str, len) ((char *)memcpy((p), str, (len))+(len)) +#define append_str(p, str) append_str2(p, str, sizeof(str)-1) +#define append_lit(p, str) append_str2(p, str, rb_strlen_lit(str)) + +#include "mjit_config.h" + +#if defined(__GNUC__) && \ + (!defined(__clang__) || \ + (defined(__clang__) && (defined(__FreeBSD__) || defined(__GLIBC__)))) +#define GCC_PIC_FLAGS "-Wfatal-errors", "-fPIC", "-shared", "-w", \ + "-pipe", +#else +#define GCC_PIC_FLAGS /* empty */ +#endif + +static const char *const CC_COMMON_ARGS[] = { + MJIT_CC_COMMON MJIT_CFLAGS GCC_PIC_FLAGS + NULL +}; + +/* GCC and CLANG executable paths. TODO: The paths should absolute + ones to prevent changing C compiler for security reasons. */ +#define CC_PATH CC_COMMON_ARGS[0] #ifdef _WIN32 #define waitpid(pid,stat_loc,options) (WaitForSingleObject((HANDLE)(pid), INFINITE), GetExitCodeProcess((HANDLE)(pid), (LPDWORD)(stat_loc)), (pid)) Index: mjit.c =================================================================== --- mjit.c (revision 64288) +++ mjit.c (revision 64289) @@ -9,38 +9,11 @@ https://github.com/ruby/ruby/blob/trunk/mjit.c#L9 /* Functions in this file are never executed on MJIT worker thread. So you can safely use Ruby methods and GC in this file. */ -#ifdef __sun -#define __EXTENSIONS__ 1 -#endif +/* To share variables privately, include mjit_worker.c instead of linking. */ +#include "mjit_worker.c" -#include "internal.h" -#include "vm_core.h" -#include "mjit.h" -#include "gc.h" #include "constant.h" #include "id_table.h" -#include "ruby_assert.h" -#include "ruby/thread.h" -#include "ruby/util.h" - -#ifdef _WIN32 -#include <winsock2.h> -#include <windows.h> -#else -#include <sys/wait.h> -#include <sys/time.h> -#include <dlfcn.h> -#endif -#include <errno.h> -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_SYS_PARAM_H -# include <sys/param.h> -#endif - -#include "dln.h" -#include "mjit_internal.h" extern int rb_thread_create_mjit_thread(void (*worker_func)(void)); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/