Embed builtin ruby scripts in miniprelude.c

Instead of reading from the files by the full-path at runtime.  As
rbinc files need to be included in distributed tarballs, the
full-paths at the packaging are unavailable at compilation times.
This commit is contained in:
Nobuyoshi Nakada 2019-11-09 19:28:45 +09:00
Родитель 4dc4b18904
Коммит dfaac2b372
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4BC7D6DF58D8DF60
3 изменённых файлов: 56 добавлений и 49 удалений

Просмотреть файл

@ -1072,7 +1072,7 @@ vm_call_iseq_optimized.inc: $(srcdir)/tool/mk_call_iseq_optimized.rb
$(MINIPRELUDE_C): $(COMPILE_PRELUDE)
$(ECHO) generating $@
$(Q) $(BASERUBY) $(srcdir)/tool/generic_erb.rb -I$(srcdir) -o $@ \
$(srcdir)/template/prelude.c.tmpl
$(srcdir)/template/prelude.c.tmpl $(BUILTIN_RB_SRCS)
$(PRELUDE_C): $(COMPILE_PRELUDE) \
$(PRELUDE_SCRIPTS)

Просмотреть файл

@ -5,55 +5,21 @@
// include from miniinits.c
static const char *
read_file(const char *fname, size_t *psize)
{
struct stat st;
char *code;
FILE *fp;
if (stat(fname, &st) != 0) {
rb_bug("stat fails: %s", fname);
}
size_t fsize = st.st_size;
if ((code = malloc(fsize + 1)) == NULL) {
rb_bug("can't allocate memory: %s (%d)", fname, (int)fsize);
}
if ((fp = fopen(fname, "rb")) == NULL) {
rb_bug("can't open file: %s", fname);
}
size_t read_size = fread(code, 1, fsize, fp);
if (read_size != fsize) {
rb_bug("can't read file enough: %s (expect %d but was %d)", fname, (int)fsize, (int)read_size);
}
code[fsize] = 0;
*psize = fsize;
return code;
}
static struct st_table *loaded_builtin_table;
rb_ast_t *rb_builtin_ast(const char *feature_name, VALUE *name_str);
void
rb_load_with_builtin_functions(const char *feature_name, const char *fname, const struct rb_builtin_function *table)
{
size_t fsize;
const char *code = read_file(fname, &fsize);
VALUE code_str = rb_utf8_str_new_static(code, fsize);
VALUE name_str = rb_sprintf("<internal:%s>", feature_name);
rb_obj_hide(code_str);
rb_ast_t *ast = rb_parser_compile_string_path(rb_parser_new(), name_str, code_str, 1);
VALUE name_str = 0;
rb_ast_t *ast = rb_builtin_ast(feature_name, &name_str);
GET_VM()->builtin_function_table = table;
const rb_iseq_t *iseq = rb_iseq_new(&ast->body, name_str, name_str, Qnil, NULL, ISEQ_TYPE_TOP);
GET_VM()->builtin_function_table = NULL;
rb_ast_dispose(ast);
free((void *)code); // code_str becomes broken.
// register (loaded iseq will not be freed)
st_insert(loaded_builtin_table, (st_data_t)feature_name, (st_data_t)iseq);

Просмотреть файл

@ -34,8 +34,17 @@ class Prelude
@output = output
@have_sublib = false
@vpath = vpath
@prelude_count = 0
@builtin_count = 0
@preludes = {}
@mains = preludes.map {|filename| translate(filename)[0]}
@mains = preludes.map do |filename|
if prelude = filename.end_with?("prelude.rb")
@prelude_count += 1
else
@builtin_count += 1
end
translate(filename, (filename unless prelude))[0]
end
@preludes.delete_if {|_, (_, _, lines, sub)| sub && lines.empty?}
end
@ -134,11 +143,47 @@ prelude_prefix_path(VALUE self)
struct prelude_env *ptr = DATA_PTR(self);
return ptr->prefix_path;
}
% end
% end
% unless preludes.empty?
#define PRELUDE_NAME(n) rb_usascii_str_new_static(prelude_name##n, sizeof(prelude_name##n)-1)
#define PRELUDE_CODE(n) rb_utf8_str_new_static(prelude_code##n.L0, sizeof(prelude_code##n))
static rb_ast_t *
prelude_ast(VALUE name, VALUE code, int line)
{
rb_ast_t *ast = rb_parser_compile_string_path(rb_parser_new(), name, code, line);
if (!ast->body.root) {
rb_ast_dispose(ast);
rb_exc_raise(rb_errinfo());
}
return ast;
}
% end
% if @builtin_count > 0
#define PRELUDE_AST(n, name_str) \
(((sizeof(prelude_name<%='##'%><%=%>n) - prefix_len - 2) == namelen) && \
(strncmp(prelude_name<%='##'%><%=%>n + prefix_len, feature_name, namelen) == 0) ? \
prelude_ast((name_str) = PRELUDE_NAME(n), PRELUDE_CODE(n), 1) : 0)
rb_ast_t *
rb_builtin_ast(const char *feature_name, VALUE *name_str)
{
const size_t prefix_len = rb_strlen_lit("<internal:");
size_t namelen = strlen(feature_name);
rb_ast_t *ast = 0;
% @preludes.each_value do |i, prelude, lines, sub|
% if sub and sub != true
if ((ast = PRELUDE_AST(<%=i%><%=%>, *name_str)) != 0) return ast;
% end
% end
return ast;
}
% end
% if @prelude_count > 0
COMPILER_WARNING_PUSH
#if GCC_VERSION_SINCE(4, 2, 0)
COMPILER_WARNING_ERROR(-Wmissing-field-initializers)
@ -160,18 +205,14 @@ prelude_eval(VALUE code, VALUE name, int line)
0, /* int debug_level; */
};
rb_ast_t *ast = rb_parser_compile_string_path(rb_parser_new(), name, code, line);
if (!ast->body.root) {
rb_ast_dispose(ast);
rb_exc_raise(rb_errinfo());
}
rb_ast_t *ast = prelude_ast(name, code, line);
rb_iseq_eval(rb_iseq_new_with_opt(&ast->body, name, name, Qnil, INT2FIX(line),
NULL, ISEQ_TYPE_TOP, &optimization));
rb_ast_dispose(ast);
}
COMPILER_WARNING_POP
% end
% end
% if @have_sublib
static VALUE
prelude_require(VALUE self, VALUE nth)
@ -185,7 +226,7 @@ prelude_require(VALUE self, VALUE nth)
ptr->loaded[n] = 1;
switch (n) {
% @preludes.each_value do |i, prelude, lines, sub|
% if sub
% if sub == true
case <%=i%><%=%>:
code = PRELUDE_CODE(<%=i%><%=%>);
name = PRELUDE_NAME(<%=i%><%=%>);
@ -205,7 +246,7 @@ prelude_require(VALUE self, VALUE nth)
void
Init_<%=init_name%><%=%>(void)
{
%unless @preludes.empty?
%unless @prelude_count.zero?
% if @have_sublib
struct prelude_env memo;
ID name = rb_intern("TMP_RUBY_PREFIX");