Make ISeq binaries portable

* Make `__FILE__` a frozen core method that return the iseq path.
* Make `load_from_binary` accept `file, path` like compile.

[Feature #17593]
[Feature #22395]
This commit is contained in:
Jean Boussier authored and Jean Boussier committed 2026-10-07 09:57:31 +02:00
1 parent 8197d2c567
commit 9ce0df6719
5 files changed
+42 -21
Notes: git 2026-10-07 07:58:03 +00:00

No files matched your search

+1
View File
@@ -96,6 +96,7 @@ firstline, predefined = __LINE__+1, %[\
core#undef_method
core#define_method
core#define_singleton_method
core#iseq_path
core#set_postexe
core#hash_merge_ptr
core#hash_merge_bang_ptr
+1
View File
@@ -95,6 +95,7 @@ bool rb_str_reembeddable_p(VALUE);
bool rb_str_embedded_shared_root_p(VALUE);
VALUE rb_str_upto_endless_each(VALUE, int (*each)(VALUE, VALUE), VALUE);
VALUE rb_str_with_debug_created_info(VALUE, VALUE, int);
VALUE rb_chilled_str_with_debug_created_info(VALUE, VALUE, int);
VALUE rb_str_frozen_bare_string(VALUE);
const char *rb_str_null_check(VALUE);
VALUE rb_str_casecmp(VALUE str1, VALUE str2);
+1
View File
@@ -63,6 +63,7 @@ void rb_lastline_set_up(VALUE val, unsigned int up);
/* vm_eval.c */
VALUE rb_current_realfilepath(void);
VALUE rb_current_filepath(void);
VALUE rb_check_block_call(VALUE, ID, int, const VALUE *, rb_block_call_func_t, VALUE);
typedef void rb_check_funcall_hook(int, VALUE, ID, int, const VALUE *, VALUE);
VALUE rb_check_funcall_with_hook_kw(VALUE recv, ID mid, int argc, const VALUE *argv,
+8 -21
View File
@@ -803,21 +803,6 @@ pm_compile_regexp_dynamic(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_
PUSH_INSN2(ret, *node_location, toregexp, INT2FIX(parse_regexp_flags(node) & 0xFF), INT2FIX(length));
}
static VALUE
pm_source_file_value(const pm_source_file_node_t *node, const pm_scope_node_t *scope_node)
{
const pm_string_t *filepath = &node->filepath;
size_t length = pm_string_length(filepath);
if (length > 0) {
rb_encoding *filepath_encoding = scope_node->filepath_encoding != NULL ? scope_node->filepath_encoding : rb_utf8_encoding();
return rb_enc_interned_str((const char *) pm_string_source(filepath), length, filepath_encoding);
}
else {
return rb_fstring_lit("<compiled>");
}
}
/**
* Return a static literal string, optionally with attached debugging
* information.
@@ -5764,8 +5749,6 @@ pm_compile_shareable_constant_literal(rb_iseq_t *iseq, const pm_node_t *node, pm
return pm_static_literal_value(iseq, node, scope_node);
case PM_STRING_NODE:
return parse_static_literal_string(iseq, scope_node, node, &((const pm_string_node_t *) node)->unescaped);
case PM_SOURCE_FILE_NODE:
return pm_source_file_value((const pm_source_file_node_t *) node, scope_node);
case PM_ARRAY_NODE: {
const pm_array_node_t *cast = (const pm_array_node_t *) node;
VALUE result = rb_ary_new_capa(cast->elements.size);
@@ -10497,17 +10480,21 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// ^^^^^^^^
if (!popped) {
const pm_source_file_node_t *cast = (const pm_source_file_node_t *) node;
VALUE string = pm_source_file_value(cast, scope_node);
int string_type;
if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FROZEN)) {
PUSH_INSN1(ret, location, putobject, string);
string_type = ISEQ_FROZEN_STRING_LITERAL_ENABLED;
}
else if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_MUTABLE)) {
PUSH_INSN1(ret, location, dupstring, string);
string_type = ISEQ_FROZEN_STRING_LITERAL_DISABLED;
}
else {
PUSH_INSN1(ret, location, dupchilledstring, string);
string_type = ISEQ_FROZEN_STRING_LITERAL_UNSET;
}
PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
PUSH_INSN1(ret, location, putobject, INT2FIX(string_type));
PUSH_SEND(ret, location, id_core_iseq_path, INT2FIX(1));
}
return;
}
+31
View File
@@ -4322,6 +4322,36 @@ m_core_set_postexe(VALUE self)
return Qnil;
}
static VALUE
m_core_iseq_path(VALUE self, VALUE frozen_string_literal_option_value)
{
rb_execution_context_t *ec = GET_EC();
rb_control_frame_t *cfp = ec->cfp;
cfp = vm_get_ruby_level_caller_cfp(ec, RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp));
if (cfp == NULL) {
return Qnil;
}
const rb_iseq_t *iseq = CFP_ISEQ(cfp);
VALUE path = rb_iseq_path(iseq);
if (RTEST(path)) {
int frozen_string_literal_option = NUM2INT(frozen_string_literal_option_value);
switch (frozen_string_literal_option) {
case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
RUBY_ASSERT(OBJ_FROZEN(path));
break;
case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
path = rb_str_resurrect(path);
break;
case ISEQ_FROZEN_STRING_LITERAL_UNSET:
path = rb_ec_str_resurrect(ec, path, true);
break;
default:
UNREACHABLE_RETURN(Qundef);
}
}
return path;
}
static VALUE
core_hash_merge(VALUE hash, long argc, const VALUE *argv, bool dup)
{
@@ -4617,6 +4647,7 @@ Init_VM(void)
rb_define_method_id(klass, id_core_set_variable_alias, m_core_set_variable_alias, 2);
rb_define_method_id(klass, id_core_undef_method, m_core_undef_method, 2);
rb_define_method_id(klass, id_core_set_postexe, m_core_set_postexe, 0);
rb_define_method_id(klass, id_core_iseq_path, m_core_iseq_path, 1);
rb_define_method_id(klass, id_core_hash_merge_ptr, m_core_hash_merge_ptr, -1);
rb_define_method_id(klass, id_core_hash_merge_bang_ptr, m_core_hash_merge_bang_ptr, -1);
rb_define_method_id(klass, id_core_hash_merge_kwd, m_core_hash_merge_kwd, 2);