зеркало из https://github.com/github/ruby.git
* introduce new ISeq binary format serializer/de-serializer
and a pre-compilation/runtime loader sample. [Feature #11788] * iseq.c: add new methods: * RubyVM::InstructionSequence#to_binary_format(extra_data = nil) * RubyVM::InstructionSequence.from_binary_format(binary) * RubyVM::InstructionSequence.from_binary_format_extra_data(binary) * compile.c: implement body of this new feature. * load.c (rb_load_internal0), iseq.c (rb_iseq_load_iseq): call RubyVM::InstructionSequence.load_iseq(fname) with loading script name if this method is defined. We can return any ISeq object as a result value. Otherwise loading will be continue as usual. This interface is not matured and is not extensible. So that we don't guarantee the future compatibility of this method. Basically, you should'nt use this method. * iseq.h: move ISEQ_MAJOR/MINOR_VERSION (and some definitions) from iseq.c. * encoding.c (rb_data_is_encoding), internal.h: added. * vm_core.h: add several supports for lazy load. * add USE_LAZY_LOAD macro to specify enable or disable of this feature. * add several fields to rb_iseq_t. * introduce new macro rb_iseq_check(). * insns.def: some check for lazy loading feature. * vm_insnhelper.c: ditto. * proc.c: ditto. * vm.c: ditto. * test/lib/iseq_loader_checker.rb: enabled iff suitable environment variables are provided. * test/runner.rb: enable lib/iseq_loader_checker.rb. * sample/iseq_loader.rb: add sample compiler and loader. $ ruby sample/iseq_loader.rb [dir] will compile all ruby scripts in [dir]. With default setting, this compile creates *.rb.yarb files in same directory of target .rb scripts. $ ruby -r sample/iseq_loader.rb [app] will run with enable to load compiled binary data. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52949 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
8f620b9b17
Коммит
3dbb390180
60
ChangeLog
60
ChangeLog
|
@ -1,3 +1,63 @@
|
|||
Tue Dec 8 22:31:58 2015 Koichi Sasada <ko1@atdot.net>
|
||||
|
||||
* introduce new ISeq binary format serializer/de-serializer
|
||||
and a pre-compilation/runtime loader sample.
|
||||
[Feature #11788]
|
||||
|
||||
* iseq.c: add new methods:
|
||||
* RubyVM::InstructionSequence#to_binary_format(extra_data = nil)
|
||||
* RubyVM::InstructionSequence.from_binary_format(binary)
|
||||
* RubyVM::InstructionSequence.from_binary_format_extra_data(binary)
|
||||
|
||||
* compile.c: implement body of this new feature.
|
||||
|
||||
* load.c (rb_load_internal0), iseq.c (rb_iseq_load_iseq):
|
||||
call RubyVM::InstructionSequence.load_iseq(fname) with
|
||||
loading script name if this method is defined.
|
||||
|
||||
We can return any ISeq object as a result value.
|
||||
Otherwise loading will be continue as usual.
|
||||
|
||||
This interface is not matured and is not extensible.
|
||||
So that we don't guarantee the future compatibility of this method.
|
||||
Basically, you should'nt use this method.
|
||||
|
||||
* iseq.h: move ISEQ_MAJOR/MINOR_VERSION (and some definitions)
|
||||
from iseq.c.
|
||||
|
||||
* encoding.c (rb_data_is_encoding), internal.h: added.
|
||||
|
||||
* vm_core.h: add several supports for lazy load.
|
||||
* add USE_LAZY_LOAD macro to specify enable or disable of
|
||||
this feature.
|
||||
* add several fields to rb_iseq_t.
|
||||
* introduce new macro rb_iseq_check().
|
||||
|
||||
* insns.def: some check for lazy loading feature.
|
||||
|
||||
* vm_insnhelper.c: ditto.
|
||||
|
||||
* proc.c: ditto.
|
||||
|
||||
* vm.c: ditto.
|
||||
|
||||
* test/lib/iseq_loader_checker.rb: enabled iff suitable
|
||||
environment variables are provided.
|
||||
|
||||
* test/runner.rb: enable lib/iseq_loader_checker.rb.
|
||||
|
||||
* sample/iseq_loader.rb: add sample compiler and loader.
|
||||
|
||||
$ ruby sample/iseq_loader.rb [dir]
|
||||
|
||||
will compile all ruby scripts in [dir].
|
||||
With default setting, this compile creates *.rb.yarb files
|
||||
in same directory of target .rb scripts.
|
||||
|
||||
$ ruby -r sample/iseq_loader.rb [app]
|
||||
|
||||
will run with enable to load compiled binary data.
|
||||
|
||||
Tue Dec 8 21:21:16 2015 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
|
||||
|
||||
* NEWS: mention about Enumerator::Lazy#grep_v.
|
||||
|
|
8
NEWS
8
NEWS
|
@ -116,6 +116,14 @@ with all sufficient information, see the ChangeLog file.
|
|||
|
||||
* Regexp/String: Updated Unicode version from 7.0.0 to 8.0.0
|
||||
|
||||
* RubyVM::InstructionSequence
|
||||
* add the following methods as a primitive tool of iseq loader.
|
||||
See sample/iseq_loader.rb for usage.
|
||||
[Feature #11788]
|
||||
* RubyVM::InstructionSequence#to_binary_format(extra_data = nil)
|
||||
* RubyVM::InstructionSequence.from_binary_format(binary)
|
||||
* RubyVM::InstructionSequence.from_binary_format_extra_data(binary)
|
||||
|
||||
* String
|
||||
|
||||
* String#+@ and String#- are added to get mutable/frozen strings.
|
||||
|
|
1431
compile.c
1431
compile.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -86,6 +86,12 @@ static const rb_data_type_t encoding_data_type = {
|
|||
#define is_data_encoding(obj) (RTYPEDDATA_P(obj) && RTYPEDDATA_TYPE(obj) == &encoding_data_type)
|
||||
#define is_obj_encoding(obj) (RB_TYPE_P((obj), T_DATA) && is_data_encoding(obj))
|
||||
|
||||
int
|
||||
rb_data_is_encoding(VALUE obj)
|
||||
{
|
||||
return is_data_encoding(obj);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
enc_new(rb_encoding *encoding)
|
||||
{
|
||||
|
|
|
@ -928,13 +928,15 @@ defineclass
|
|||
rb_bug("unknown defineclass type: %d", (int)type);
|
||||
}
|
||||
|
||||
rb_iseq_check(class_iseq);
|
||||
|
||||
/* enter scope */
|
||||
vm_push_frame(th, class_iseq, VM_FRAME_MAGIC_CLASS, klass,
|
||||
VM_ENVVAL_BLOCK_PTR(GET_BLOCK_PTR()),
|
||||
(VALUE)vm_cref_push(th, klass, NULL, FALSE),
|
||||
class_iseq->body->iseq_encoded, GET_SP(),
|
||||
class_iseq->body->local_size, class_iseq->body->stack_max);
|
||||
|
||||
class_iseq->body->local_size,
|
||||
class_iseq->body->stack_max);
|
||||
RESTORE_REGS();
|
||||
NEXT_INSN();
|
||||
}
|
||||
|
|
|
@ -725,6 +725,7 @@ void rb_encdb_declare(const char *name);
|
|||
void rb_enc_set_base(const char *name, const char *orig);
|
||||
int rb_enc_set_dummy(int index);
|
||||
void rb_encdb_set_unicode(int index);
|
||||
int rb_data_is_encoding(VALUE obj);
|
||||
|
||||
/* enum.c */
|
||||
VALUE rb_f_send(int argc, VALUE *argv, VALUE recv);
|
||||
|
|
149
iseq.c
149
iseq.c
|
@ -25,9 +25,6 @@
|
|||
#include "insns.inc"
|
||||
#include "insns_info.inc"
|
||||
|
||||
#define ISEQ_MAJOR_VERSION 2
|
||||
#define ISEQ_MINOR_VERSION 3
|
||||
|
||||
VALUE rb_cISeq;
|
||||
static VALUE iseqw_new(const rb_iseq_t *iseq);
|
||||
static const rb_iseq_t *iseqw_check(VALUE iseqw);
|
||||
|
@ -71,30 +68,32 @@ rb_iseq_free(const rb_iseq_t *iseq)
|
|||
RUBY_FREE_ENTER("iseq");
|
||||
|
||||
if (iseq) {
|
||||
ruby_xfree((void *)iseq->body->iseq_encoded);
|
||||
ruby_xfree((void *)iseq->body->line_info_table);
|
||||
ruby_xfree((void *)iseq->body->local_table);
|
||||
ruby_xfree((void *)iseq->body->is_entries);
|
||||
if (iseq->body) {
|
||||
ruby_xfree((void *)iseq->body->iseq_encoded);
|
||||
ruby_xfree((void *)iseq->body->line_info_table);
|
||||
ruby_xfree((void *)iseq->body->local_table);
|
||||
ruby_xfree((void *)iseq->body->is_entries);
|
||||
|
||||
if (iseq->body->ci_entries) {
|
||||
unsigned int i;
|
||||
struct rb_call_info_with_kwarg *ci_kw_entries = (struct rb_call_info_with_kwarg *)&iseq->body->ci_entries[iseq->body->ci_size];
|
||||
for (i=0; i<iseq->body->ci_kw_size; i++) {
|
||||
const struct rb_call_info_kw_arg *kw_arg = ci_kw_entries[i].kw_arg;
|
||||
ruby_xfree((void *)kw_arg);
|
||||
if (iseq->body->ci_entries) {
|
||||
unsigned int i;
|
||||
struct rb_call_info_with_kwarg *ci_kw_entries = (struct rb_call_info_with_kwarg *)&iseq->body->ci_entries[iseq->body->ci_size];
|
||||
for (i=0; i<iseq->body->ci_kw_size; i++) {
|
||||
const struct rb_call_info_kw_arg *kw_arg = ci_kw_entries[i].kw_arg;
|
||||
ruby_xfree((void *)kw_arg);
|
||||
}
|
||||
ruby_xfree(iseq->body->ci_entries);
|
||||
ruby_xfree(iseq->body->cc_entries);
|
||||
}
|
||||
ruby_xfree(iseq->body->ci_entries);
|
||||
ruby_xfree(iseq->body->cc_entries);
|
||||
}
|
||||
ruby_xfree((void *)iseq->body->catch_table);
|
||||
ruby_xfree((void *)iseq->body->param.opt_table);
|
||||
ruby_xfree((void *)iseq->body->catch_table);
|
||||
ruby_xfree((void *)iseq->body->param.opt_table);
|
||||
|
||||
if (iseq->body->param.keyword != NULL) {
|
||||
ruby_xfree((void *)iseq->body->param.keyword->default_values);
|
||||
ruby_xfree((void *)iseq->body->param.keyword);
|
||||
if (iseq->body->param.keyword != NULL) {
|
||||
ruby_xfree((void *)iseq->body->param.keyword->default_values);
|
||||
ruby_xfree((void *)iseq->body->param.keyword);
|
||||
}
|
||||
compile_data_free(ISEQ_COMPILE_DATA(iseq));
|
||||
ruby_xfree(iseq->body);
|
||||
}
|
||||
compile_data_free(ISEQ_COMPILE_DATA(iseq));
|
||||
ruby_xfree(iseq->body);
|
||||
}
|
||||
RUBY_FREE_LEAVE("iseq");
|
||||
}
|
||||
|
@ -116,9 +115,11 @@ rb_iseq_mark(const rb_iseq_t *iseq)
|
|||
RUBY_MARK_UNLESS_NULL(body->location.absolute_path);
|
||||
}
|
||||
|
||||
if (ISEQ_COMPILE_DATA(iseq) != 0) {
|
||||
if (FL_TEST(iseq, ISEQ_NOT_LOADED_YET)) {
|
||||
rb_gc_mark(iseq->aux.loader.obj);
|
||||
}
|
||||
else if (ISEQ_COMPILE_DATA(iseq) != 0) {
|
||||
const struct iseq_compile_data *const compile_data = ISEQ_COMPILE_DATA(iseq);
|
||||
|
||||
RUBY_MARK_UNLESS_NULL(compile_data->mark_ary);
|
||||
RUBY_MARK_UNLESS_NULL(compile_data->err_info);
|
||||
RUBY_MARK_UNLESS_NULL(compile_data->catch_table_ary);
|
||||
|
@ -205,7 +206,7 @@ iseq_memsize(const rb_iseq_t *iseq)
|
|||
static rb_iseq_t *
|
||||
iseq_alloc(void)
|
||||
{
|
||||
rb_iseq_t *iseq = (rb_iseq_t *)rb_imemo_new(imemo_iseq, 0, 0, 0, 0);
|
||||
rb_iseq_t *iseq = iseq_imemo_alloc();
|
||||
iseq->body = ZALLOC(struct rb_iseq_constant_body);
|
||||
return iseq;
|
||||
}
|
||||
|
@ -259,16 +260,6 @@ rb_iseq_add_mark_object(const rb_iseq_t *iseq, VALUE obj)
|
|||
rb_ary_push(ISEQ_MARK_ARY(iseq), obj);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
iseq_mark_ary_create(int flip_cnt)
|
||||
{
|
||||
VALUE ary = rb_ary_tmp_new(3);
|
||||
rb_ary_push(ary, Qnil); /* ISEQ_MARK_ARY_COVERAGE */
|
||||
rb_ary_push(ary, INT2FIX(flip_cnt)); /* ISEQ_MARK_ARY_FLIP_CNT */
|
||||
rb_ary_push(ary, Qnil); /* ISEQ_MARK_ARY_ORIGINAL_ISEQ */
|
||||
return ary;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
prepare_iseq_build(rb_iseq_t *iseq,
|
||||
VALUE name, VALUE path, VALUE absolute_path, VALUE first_lineno,
|
||||
|
@ -485,6 +476,19 @@ rb_iseq_new_with_opt(NODE *node, VALUE name, VALUE path, VALUE absolute_path,
|
|||
return iseq_translate(iseq);
|
||||
}
|
||||
|
||||
const rb_iseq_t *
|
||||
rb_iseq_load_iseq(VALUE fname)
|
||||
{
|
||||
if (rb_respond_to(rb_cISeq, rb_intern("load_iseq"))) {
|
||||
VALUE iseqv = rb_funcall(rb_cISeq, rb_intern("load_iseq"), 1, fname);
|
||||
if (CLASS_OF(iseqv) == rb_cISeq) {
|
||||
return iseqw_check(iseqv);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define CHECK_ARRAY(v) rb_convert_type((v), T_ARRAY, "Array", "to_ary")
|
||||
#define CHECK_HASH(v) rb_convert_type((v), T_HASH, "Hash", "to_hash")
|
||||
#define CHECK_STRING(v) rb_convert_type((v), T_STRING, "String", "to_str")
|
||||
|
@ -583,8 +587,7 @@ static VALUE
|
|||
iseq_s_load(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE data, opt=Qnil;
|
||||
rb_scan_args(argc, argv, "11", &data, &opt);
|
||||
|
||||
rb_scan_args(argc, argv, "01", &opt);
|
||||
return iseq_load(data, NULL, opt);
|
||||
}
|
||||
|
||||
|
@ -892,7 +895,11 @@ iseqw_s_compile_option_get(VALUE self)
|
|||
static const rb_iseq_t *
|
||||
iseqw_check(VALUE iseqw)
|
||||
{
|
||||
const rb_iseq_t *iseq = DATA_PTR(iseqw);
|
||||
rb_iseq_t *iseq = DATA_PTR(iseqw);
|
||||
|
||||
if (!iseq->body) {
|
||||
ibf_load_iseq_complete(iseq);
|
||||
}
|
||||
|
||||
if (!iseq->body->location.label) {
|
||||
rb_raise(rb_eTypeError, "uninitialized InstructionSequence");
|
||||
|
@ -1235,7 +1242,7 @@ rb_insn_operand_intern(const rb_iseq_t *iseq,
|
|||
{
|
||||
const char *types = insn_op_types(insn);
|
||||
char type = types[op_no];
|
||||
VALUE ret;
|
||||
VALUE ret = Qundef;
|
||||
|
||||
switch (type) {
|
||||
case TS_OFFSET: /* LONG */
|
||||
|
@ -1281,8 +1288,8 @@ rb_insn_operand_intern(const rb_iseq_t *iseq,
|
|||
|
||||
case TS_ISEQ: /* iseq */
|
||||
{
|
||||
rb_iseq_t *iseq = (rb_iseq_t *)op;
|
||||
if (iseq) {
|
||||
if (op) {
|
||||
const rb_iseq_t *iseq = rb_iseq_check((rb_iseq_t *)op);
|
||||
ret = iseq->body->location.label;
|
||||
if (child) {
|
||||
rb_ary_push(child, (VALUE)iseq);
|
||||
|
@ -1492,7 +1499,7 @@ rb_iseq_disasm(const rb_iseq_t *iseq)
|
|||
catch_type((int)entry->type), (int)entry->start,
|
||||
(int)entry->end, (int)entry->sp, (int)entry->cont);
|
||||
if (entry->iseq) {
|
||||
rb_str_concat(str, rb_iseq_disasm(entry->iseq));
|
||||
rb_str_concat(str, rb_iseq_disasm(rb_iseq_check(entry->iseq)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1561,7 +1568,7 @@ rb_iseq_disasm(const rb_iseq_t *iseq)
|
|||
|
||||
for (l = 0; l < RARRAY_LEN(child); l++) {
|
||||
VALUE isv = rb_ary_entry(child, l);
|
||||
rb_str_concat(str, rb_iseq_disasm((rb_iseq_t *)isv));
|
||||
rb_str_concat(str, rb_iseq_disasm(rb_iseq_check((rb_iseq_t *)isv)));
|
||||
}
|
||||
|
||||
return str;
|
||||
|
@ -1907,7 +1914,7 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
|
|||
{
|
||||
const rb_iseq_t *iseq = (rb_iseq_t *)*seq;
|
||||
if (iseq) {
|
||||
VALUE val = iseq_data_to_ary(iseq);
|
||||
VALUE val = iseq_data_to_ary(rb_iseq_check(iseq));
|
||||
rb_ary_push(ary, val);
|
||||
}
|
||||
else {
|
||||
|
@ -2002,7 +2009,7 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
|
|||
const struct iseq_catch_table_entry *entry = &iseq->body->catch_table->entries[i];
|
||||
rb_ary_push(ary, exception_type2symbol(entry->type));
|
||||
if (entry->iseq) {
|
||||
rb_ary_push(ary, iseq_data_to_ary(entry->iseq));
|
||||
rb_ary_push(ary, iseq_data_to_ary(rb_iseq_check(entry->iseq)));
|
||||
}
|
||||
else {
|
||||
rb_ary_push(ary, Qnil);
|
||||
|
@ -2325,6 +2332,51 @@ rb_iseqw_local_variables(VALUE iseqval)
|
|||
return rb_iseq_local_variables(iseqw_check(iseqval));
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* iseq.to_binary_format(extra_data = nil) -> binary str
|
||||
*
|
||||
* Returns serialized iseq binary format data as a String object.
|
||||
* A correspnding iseq object is created by
|
||||
* RubyVM::InstructionSequence.from_binary_format() method.
|
||||
*
|
||||
* String extra_data will be saved with binary data.
|
||||
* You can access this data with
|
||||
* RubyVM::InstructionSequence.from_binary_format_extra_data(binary).
|
||||
*/
|
||||
static VALUE
|
||||
iseqw_to_binary_format(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE opt;
|
||||
rb_scan_args(argc, argv, "01", &opt);
|
||||
return iseq_ibf_dump(iseqw_check(self), opt);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RubyVM::InstructionSequence.from_binary_format(binary) -> iseq
|
||||
*
|
||||
* Load an iseq object from binary format String object
|
||||
* created by RubyVM::InstructionSequence.to_binary_format.
|
||||
*/
|
||||
static VALUE
|
||||
iseqw_s_from_binary_format(VALUE self, VALUE str)
|
||||
{
|
||||
return iseqw_new(iseq_ibf_load(str));
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RubyVM::InstructionSequence.from_binary_format_extra_data(binary) -> str
|
||||
*
|
||||
* Load extra data embed into binary format String object.
|
||||
*/
|
||||
static VALUE
|
||||
iseqw_s_from_binary_format_extra_data(VALUE self, VALUE str)
|
||||
{
|
||||
return iseq_ibf_load_extra_data(str);
|
||||
}
|
||||
|
||||
/*
|
||||
* Document-class: RubyVM::InstructionSequence
|
||||
*
|
||||
|
@ -2356,6 +2408,11 @@ Init_ISeq(void)
|
|||
rb_define_method(rb_cISeq, "to_a", iseqw_to_a, 0);
|
||||
rb_define_method(rb_cISeq, "eval", iseqw_eval, 0);
|
||||
|
||||
rb_define_method(rb_cISeq, "to_binary_format", iseqw_to_binary_format, -1);
|
||||
rb_define_singleton_method(rb_cISeq, "from_binary_format", iseqw_s_from_binary_format, 1);
|
||||
rb_define_singleton_method(rb_cISeq, "from_binary_format_extra_data", iseqw_s_from_binary_format_extra_data, 1);
|
||||
|
||||
|
||||
/* location APIs */
|
||||
rb_define_method(rb_cISeq, "path", iseqw_path, 0);
|
||||
rb_define_method(rb_cISeq, "absolute_path", iseqw_absolute_path, 0);
|
||||
|
|
33
iseq.h
33
iseq.h
|
@ -12,6 +12,9 @@
|
|||
#ifndef RUBY_ISEQ_H
|
||||
#define RUBY_ISEQ_H 1
|
||||
|
||||
#define ISEQ_MAJOR_VERSION 2
|
||||
#define ISEQ_MINOR_VERSION 3
|
||||
|
||||
#ifndef rb_iseq_t
|
||||
typedef struct rb_iseq_struct rb_iseq_t;
|
||||
#define rb_iseq_t rb_iseq_t
|
||||
|
@ -29,16 +32,27 @@ enum iseq_mark_ary_index {
|
|||
ISEQ_MARK_ARY_ORIGINAL_ISEQ = 2,
|
||||
};
|
||||
|
||||
static inline VALUE
|
||||
iseq_mark_ary_create(int flip_cnt)
|
||||
{
|
||||
VALUE ary = rb_ary_tmp_new(3);
|
||||
rb_ary_push(ary, Qnil); /* ISEQ_MARK_ARY_COVERAGE */
|
||||
rb_ary_push(ary, INT2FIX(flip_cnt)); /* ISEQ_MARK_ARY_FLIP_CNT */
|
||||
rb_ary_push(ary, Qnil); /* ISEQ_MARK_ARY_ORIGINAL_ISEQ */
|
||||
return ary;
|
||||
}
|
||||
|
||||
#define ISEQ_MARK_ARY(iseq) (iseq)->body->mark_ary
|
||||
|
||||
#define ISEQ_COVERAGE(iseq) RARRAY_AREF(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_COVERAGE)
|
||||
#define ISEQ_COVERAGE_SET(iseq, cov) RARRAY_ASET(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_COVERAGE, cov)
|
||||
|
||||
#define ISEQ_FLIP_CNT(iseq) FIX2INT(RARRAY_AREF(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_FLIP_CNT))
|
||||
|
||||
static inline int
|
||||
ISEQ_FLIP_CNT_INCREMENT(const rb_iseq_t *iseq)
|
||||
{
|
||||
VALUE cntv = RARRAY_AREF(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_FLIP_CNT);
|
||||
int cnt = FIX2INT(cntv);
|
||||
int cnt = ISEQ_FLIP_CNT(iseq);
|
||||
RARRAY_ASET(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_FLIP_CNT, INT2FIX(cnt+1));
|
||||
return cnt;
|
||||
}
|
||||
|
@ -59,7 +73,20 @@ ISEQ_ORIGINAL_ISEQ_ALLOC(const rb_iseq_t *iseq, long size)
|
|||
return (VALUE *)RSTRING_PTR(str);
|
||||
}
|
||||
|
||||
#define ISEQ_COMPILE_DATA(iseq) (iseq)->compile_data_
|
||||
#define ISEQ_COMPILE_DATA(iseq) (iseq)->aux.compile_data
|
||||
|
||||
static inline rb_iseq_t *
|
||||
iseq_imemo_alloc(void)
|
||||
{
|
||||
return (rb_iseq_t *)rb_imemo_new(imemo_iseq, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
#define ISEQ_NOT_LOADED_YET IMEMO_FL_USER1
|
||||
|
||||
VALUE iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt);
|
||||
void ibf_load_iseq_complete(rb_iseq_t *iseq);
|
||||
const rb_iseq_t *iseq_ibf_load(VALUE str);
|
||||
VALUE iseq_ibf_load_extra_data(VALUE str);
|
||||
|
||||
RUBY_SYMBOL_EXPORT_BEGIN
|
||||
|
||||
|
|
16
load.c
16
load.c
|
@ -575,6 +575,7 @@ rb_provide(const char *feature)
|
|||
}
|
||||
|
||||
NORETURN(static void load_failed(VALUE));
|
||||
const rb_iseq_t *rb_iseq_load_iseq(VALUE fname);
|
||||
|
||||
static int
|
||||
rb_load_internal0(rb_thread_t *th, VALUE fname, int wrap)
|
||||
|
@ -604,12 +605,17 @@ rb_load_internal0(rb_thread_t *th, VALUE fname, int wrap)
|
|||
state = EXEC_TAG();
|
||||
if (state == 0) {
|
||||
NODE *node;
|
||||
rb_iseq_t *iseq;
|
||||
const rb_iseq_t *iseq;
|
||||
|
||||
th->mild_compile_error++;
|
||||
node = (NODE *)rb_load_file_str(fname);
|
||||
iseq = rb_iseq_new_top(node, rb_str_new2("<top (required)>"), fname, rb_realpath_internal(Qnil, fname, 1), NULL);
|
||||
th->mild_compile_error--;
|
||||
if ((iseq = rb_iseq_load_iseq(fname)) != NULL) {
|
||||
/* OK */
|
||||
}
|
||||
else {
|
||||
th->mild_compile_error++;
|
||||
node = (NODE *)rb_load_file_str(fname);
|
||||
iseq = rb_iseq_new_top(node, rb_str_new2("<top (required)>"), fname, rb_realpath_internal(Qnil, fname, 1), NULL);
|
||||
th->mild_compile_error--;
|
||||
}
|
||||
rb_iseq_eval(iseq);
|
||||
}
|
||||
TH_POP_TAG();
|
||||
|
|
13
proc.c
13
proc.c
|
@ -984,12 +984,15 @@ rb_proc_get_iseq(VALUE self, int *is_proc)
|
|||
iseq = rb_method_iseq((VALUE)ifunc->data);
|
||||
if (is_proc) *is_proc = 0;
|
||||
}
|
||||
return iseq;
|
||||
}
|
||||
else if (SYMBOL_P(iseq)) {
|
||||
self = rb_sym_to_proc((VALUE)iseq);
|
||||
goto again;
|
||||
}
|
||||
return iseq;
|
||||
else {
|
||||
return rb_iseq_check(iseq);
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
|
@ -998,6 +1001,7 @@ iseq_location(const rb_iseq_t *iseq)
|
|||
VALUE loc[2];
|
||||
|
||||
if (!iseq) return Qnil;
|
||||
rb_iseq_check(iseq);
|
||||
loc[0] = iseq->body->location.path;
|
||||
if (iseq->body->line_info_table) {
|
||||
loc[1] = rb_iseq_first_lineno(iseq);
|
||||
|
@ -1142,7 +1146,7 @@ proc_to_s(VALUE self)
|
|||
iseq = proc->block.iseq;
|
||||
is_lambda = proc->is_lambda ? " (lambda)" : "";
|
||||
|
||||
if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
|
||||
if (RUBY_VM_NORMAL_ISEQ_P(iseq) && rb_iseq_check(iseq)) {
|
||||
int first_lineno = 0;
|
||||
|
||||
if (iseq->body->line_info_table) {
|
||||
|
@ -2152,7 +2156,7 @@ rb_method_entry_min_max_arity(const rb_method_entry_t *me, int *max)
|
|||
case VM_METHOD_TYPE_BMETHOD:
|
||||
return rb_proc_min_max_arity(def->body.proc, max);
|
||||
case VM_METHOD_TYPE_ISEQ: {
|
||||
const rb_iseq_t *iseq = def->body.iseq.iseqptr;
|
||||
const rb_iseq_t *iseq = rb_iseq_check(def->body.iseq.iseqptr);
|
||||
return rb_iseq_min_max_arity(iseq, max);
|
||||
}
|
||||
case VM_METHOD_TYPE_UNDEF:
|
||||
|
@ -2289,7 +2293,7 @@ method_def_iseq(const rb_method_definition_t *def)
|
|||
{
|
||||
switch (def->type) {
|
||||
case VM_METHOD_TYPE_ISEQ:
|
||||
return def->body.iseq.iseqptr;
|
||||
return rb_iseq_check(def->body.iseq.iseqptr);
|
||||
case VM_METHOD_TYPE_BMETHOD:
|
||||
return get_proc_iseq(def->body.proc, 0);
|
||||
case VM_METHOD_TYPE_ALIAS:
|
||||
|
@ -2654,6 +2658,7 @@ proc_binding(VALUE self)
|
|||
bind->env = envval;
|
||||
|
||||
if (iseq) {
|
||||
rb_iseq_check(iseq);
|
||||
bind->path = iseq->body->location.path;
|
||||
bind->first_lineno = FIX2INT(rb_iseq_first_lineno(iseq));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,240 @@
|
|||
#
|
||||
# iseq_loader.rb - sample of compiler/loader for binary compiled file
|
||||
#
|
||||
# Usage as a compiler: ruby iseq_loader.rb [file or directory] ...
|
||||
#
|
||||
# It compiles and stores specified files.
|
||||
# If directories are specified, then compiles and stores all *.rb files.
|
||||
# (using Dir.glob)
|
||||
#
|
||||
# TODO: add remove option
|
||||
# TODO: add verify option
|
||||
#
|
||||
# Usage as a loader: simply require this file with the following setting.
|
||||
#
|
||||
# Setting with environment variables.
|
||||
#
|
||||
# * RUBY_ISEQ_LOADER_STORAGE to select storage type
|
||||
# * dbm: use dbm
|
||||
# * fs: [default] use file system. locate a compiled binary files in same
|
||||
# directory of scripts like Rubinius. foo.rb.yarb will be created for foo.rb.
|
||||
# * fs2: use file system. locate compiled file in specified directory.
|
||||
# * nothing: do nothing.
|
||||
#
|
||||
# * RUBY_ISEQ_LOADER_STORAGE_DIR to select directory
|
||||
# * default: ~/.ruby_binaries/
|
||||
#
|
||||
# * RUBY_ISEQ_LOADER_STORAGE_COMPILE_IF_NOT_COMPILED
|
||||
# * true: store compiled file if compiled data is not available.
|
||||
# * false: [default] do nothing if there is no compiled iseq data.
|
||||
|
||||
class RubyVM::InstructionSequence
|
||||
$ISEQ_LOADER_LOADED = 0
|
||||
$ISEQ_LOADER_COMPILED = 0
|
||||
$ISEQ_LOADER_IGNORED = 0
|
||||
LAUNCHED_TIME = Time.now
|
||||
COMPILE_FILE_ENABLE = false || true
|
||||
COMPILE_VERBOSE = $VERBOSE || false # || true
|
||||
COMPILE_DEBUG = ENV['RUBY_ISEQ_LOADER_DEBUG']
|
||||
COMPILE_IF_NOT_COMPILED = ENV['RUBY_ISEQ_LOADER_STORAGE_COMPILE_IF_NOT_COMPILED'] == 'true'
|
||||
|
||||
at_exit{
|
||||
STDERR.puts "[ISEQ_LOADER] #{Process.pid} time: #{Time.now - LAUNCHED_TIME}, " +
|
||||
"loaded: #{$ISEQ_LOADER_LOADED}, " +
|
||||
"compied: #{$ISEQ_LOADER_COMPILED}, " +
|
||||
"ignored: #{$ISEQ_LOADER_IGNORED}"
|
||||
} if COMPILE_VERBOSE
|
||||
|
||||
unless cf_dir = ENV['RUBY_ISEQ_LOADER_STORAGE_DIR']
|
||||
cf_dir = File.expand_path("~/.ruby_binaries")
|
||||
unless File.exist?(cf_dir)
|
||||
Dir.mkdir(cf_dir)
|
||||
end
|
||||
end
|
||||
CF_PREFIX = "#{cf_dir}/cb."
|
||||
|
||||
class NullStorage
|
||||
def load_iseq fname; end
|
||||
def compile_and_save_isq fname; end
|
||||
def unlink_compiled_iseq; end
|
||||
end
|
||||
|
||||
class BasicStorage
|
||||
def initialize
|
||||
require 'digest/sha1'
|
||||
end
|
||||
|
||||
def load_iseq fname
|
||||
iseq_key = iseq_key_name(fname)
|
||||
if compiled_iseq_exist?(fname, iseq_key) && compiled_iseq_is_younger?(fname, iseq_key)
|
||||
$ISEQ_LOADER_LOADED += 1
|
||||
STDERR.puts "[ISEQ_LOADER] #{Process.pid} load #{fname} from #{iseq_key}" if COMPILE_DEBUG
|
||||
binary = read_compiled_iseq(fname, iseq_key)
|
||||
RubyVM::InstructionSequence.from_binary_format(binary)
|
||||
elsif COMPILE_IF_NOT_COMPILED
|
||||
compile_and_save_iseq(fname, iseq_key)
|
||||
else
|
||||
$ISEQ_LOADER_IGNORED += 1
|
||||
# p fname
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def extra_data fname
|
||||
"SHA-1:#{::Digest::SHA1.file(fname).digest}"
|
||||
end
|
||||
|
||||
def compile_and_save_iseq fname, iseq_key = iseq_key_name(fname)
|
||||
$ISEQ_LOADER_COMPILED += 1
|
||||
STDERR.puts "[RUBY_COMPILED_FILE] compile #{fname}" if COMPILE_DEBUG
|
||||
iseq = RubyVM::InstructionSequence.compile_file(fname)
|
||||
|
||||
binary = iseq.to_binary_format(extra_data(fname))
|
||||
write_compiled_iseq(fname, iseq_key, binary)
|
||||
iseq
|
||||
end
|
||||
|
||||
# def unlink_compiled_iseq; nil; end # should implement at sub classes
|
||||
|
||||
private
|
||||
|
||||
def iseq_key_name fname
|
||||
fname
|
||||
end
|
||||
|
||||
# should implement at sub classes
|
||||
# def compiled_iseq_younger? fname, iseq_key; end
|
||||
# def compiled_iseq_exist? fname, iseq_key; end
|
||||
# def read_compiled_file fname, iseq_key; end
|
||||
# def write_compiled_file fname, iseq_key, binary; end
|
||||
end
|
||||
|
||||
class FSStorage < BasicStorage
|
||||
def initialize
|
||||
super
|
||||
require 'fileutils'
|
||||
@dir = CF_PREFIX + "files"
|
||||
unless File.directory?(@dir)
|
||||
FileUtils.mkdir_p(@dir)
|
||||
end
|
||||
end
|
||||
|
||||
def unlink_compiled_iseq
|
||||
File.unlink(compile_file_path)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def iseq_key_name fname
|
||||
"#{fname}.yarb" # same directory
|
||||
end
|
||||
|
||||
def compiled_iseq_exist? fname, iseq_key
|
||||
File.exist?(iseq_key)
|
||||
end
|
||||
|
||||
def compiled_iseq_is_younger? fname, iseq_key
|
||||
File.mtime(iseq_key) >= File.mtime(fname)
|
||||
end
|
||||
|
||||
def read_compiled_iseq fname, iseq_key
|
||||
open(iseq_key, 'rb'){|f| f.read}
|
||||
end
|
||||
|
||||
def write_compiled_iseq fname, iseq_key, binary
|
||||
open(iseq_key, 'wb'){|f| f.write(binary)}
|
||||
end
|
||||
end
|
||||
|
||||
class FS2Storage < FSStorage
|
||||
def iseq_key_name fname
|
||||
@dir + fname.gsub(/[^A-Za-z0-9\._-]/){|c| '%02x' % c.ord} # special directory
|
||||
end
|
||||
end
|
||||
|
||||
class DBMStorage < BasicStorage
|
||||
def initialize
|
||||
require 'dbm'
|
||||
@db = DBM.open(CF_PREFIX+'db')
|
||||
end
|
||||
|
||||
def unlink_compiled_iseq
|
||||
@db.delete fname
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def date_key_name fname
|
||||
"date.#{fname}"
|
||||
end
|
||||
|
||||
def iseq_key_name fname
|
||||
"body.#{fname}"
|
||||
end
|
||||
|
||||
def compiled_iseq_exist? fname, iseq_key
|
||||
@db.has_key? iseq_key
|
||||
end
|
||||
|
||||
def compiled_iseq_is_younger? fname, iseq_key
|
||||
date_key = date_key_name(fname)
|
||||
if @db.has_key? date_key
|
||||
@db[date_key].to_i >= File.mtime(fname).to_i
|
||||
end
|
||||
end
|
||||
|
||||
def read_compiled_iseq fname, iseq_key
|
||||
@db[iseq_key]
|
||||
end
|
||||
|
||||
def write_compiled_iseq fname, iseq_key, binary
|
||||
date_key = date_key_name(fname)
|
||||
@db[iseq_key] = binary
|
||||
@db[date_key] = Time.now.to_i
|
||||
end
|
||||
end
|
||||
|
||||
STORAGE = case ENV['RUBY_ISEQ_LOADER_STORAGE']
|
||||
when 'dbm'
|
||||
DBMStorage.new
|
||||
when 'fs'
|
||||
FSStorage.new
|
||||
when 'fs2'
|
||||
FS2Storage.new
|
||||
when 'null'
|
||||
NullStorage.new
|
||||
else
|
||||
FSStorage.new
|
||||
end
|
||||
|
||||
STDERR.puts "[ISEQ_LOADER] use #{STORAGE.class} " if COMPILE_VERBOSE
|
||||
|
||||
def self.load_iseq fname
|
||||
STORAGE.load_iseq(fname)
|
||||
end
|
||||
|
||||
def self.compile_and_save_iseq fname
|
||||
STORAGE.compile_and_save_iseq fname
|
||||
end
|
||||
|
||||
def self.unlink_compiled_iseq fname
|
||||
STORAGE.unlink_compiled_iseq fname
|
||||
end
|
||||
end
|
||||
|
||||
if __FILE__ == $0
|
||||
ARGV.each{|path|
|
||||
if File.directory?(path)
|
||||
pattern = File.join(path, '**/*.rb')
|
||||
Dir.glob(pattern){|file|
|
||||
begin
|
||||
RubyVM::InstructionSequence.compile_and_save_iseq(file)
|
||||
rescue SyntaxError => e
|
||||
STDERR.puts e
|
||||
end
|
||||
}
|
||||
else
|
||||
RubyVM::InstructionSequence.compile_and_save_iseq(path)
|
||||
end
|
||||
}
|
||||
end
|
|
@ -1,5 +1,8 @@
|
|||
|
||||
require '-test-/iseq_load/iseq_load'
|
||||
begin
|
||||
require '-test-/iseq_load/iseq_load'
|
||||
rescue LoadError
|
||||
end
|
||||
require 'tempfile'
|
||||
|
||||
class RubyVM::InstructionSequence
|
||||
|
@ -21,9 +24,6 @@ class RubyVM::InstructionSequence
|
|||
d2 = i2.disasm_if_possible
|
||||
|
||||
if d1 != d2
|
||||
p i1
|
||||
return
|
||||
|
||||
STDERR.puts "expected:"
|
||||
STDERR.puts d1
|
||||
STDERR.puts "actual:"
|
||||
|
@ -37,19 +37,38 @@ class RubyVM::InstructionSequence
|
|||
i2
|
||||
end
|
||||
|
||||
CHECK_TO_A = ENV['RUBY_ISEQ_DUMP_DEBUG'] == 'to_a'
|
||||
CHECK_TO_BINARY = ENV['RUBY_ISEQ_DUMP_DEBUG'] == 'to_binary'
|
||||
|
||||
def self.translate i1
|
||||
# check to_a/load_iseq
|
||||
i2 = compare_dump_and_load(i1,
|
||||
proc{|iseq|
|
||||
ary = iseq.to_a
|
||||
ary[9] == :top ? ary : nil
|
||||
},
|
||||
proc{|ary|
|
||||
RubyVM::InstructionSequence.iseq_load(ary)
|
||||
})
|
||||
i2_ary = compare_dump_and_load(i1,
|
||||
proc{|iseq|
|
||||
ary = iseq.to_a
|
||||
ary[9] == :top ? ary : nil
|
||||
},
|
||||
proc{|ary|
|
||||
RubyVM::InstructionSequence.iseq_load(ary)
|
||||
}) if CHECK_TO_A && defined?(RubyVM::InstructionSequence.iseq_load)
|
||||
|
||||
# check to_binary_format
|
||||
i2_bin = compare_dump_and_load(i1,
|
||||
proc{|iseq|
|
||||
begin
|
||||
iseq.to_binary_format
|
||||
rescue RuntimeError => e # not a toplevel
|
||||
# STDERR.puts [:failed, e, iseq].inspect
|
||||
nil
|
||||
end
|
||||
},
|
||||
proc{|bin|
|
||||
iseq = RubyVM::InstructionSequence.from_binary_format(bin)
|
||||
# STDERR.puts iseq.inspect
|
||||
iseq
|
||||
}) if CHECK_TO_BINARY
|
||||
# return value
|
||||
i1
|
||||
end
|
||||
i2_bin if CHECK_TO_BINARY
|
||||
end if CHECK_TO_A || CHECK_TO_BINARY
|
||||
end
|
||||
|
||||
#require_relative 'x'; exit(1)
|
||||
|
|
|
@ -22,7 +22,7 @@ ENV["GEM_SKIP"] = ENV["GEM_HOME"] = ENV["GEM_PATH"] = "".freeze
|
|||
require_relative 'lib/profile_test_all' if ENV.has_key?('RUBY_TEST_ALL_PROFILE')
|
||||
require_relative 'lib/tracepointchecker'
|
||||
require_relative 'lib/zombie_hunter'
|
||||
# require_relative 'lib/iseq_loader_checker'
|
||||
require_relative 'lib/iseq_loader_checker'
|
||||
|
||||
if ENV['COVERAGE']
|
||||
%w[doclie simplecov-html simplecov].each do |f|
|
||||
|
|
3
vm.c
3
vm.c
|
@ -945,7 +945,7 @@ invoke_block_from_c_0(rb_thread_t *th, const rb_block_t *block,
|
|||
return Qnil;
|
||||
}
|
||||
else if (LIKELY(RUBY_VM_NORMAL_ISEQ_P(block->iseq))) {
|
||||
const rb_iseq_t *iseq = block->iseq;
|
||||
const rb_iseq_t *iseq = rb_iseq_check(block->iseq);
|
||||
int i, opt_pc;
|
||||
int type = block_proc_is_lambda(block->proc) ? VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK;
|
||||
VALUE *sp = th->cfp->sp;
|
||||
|
@ -1816,6 +1816,7 @@ vm_exec(rb_thread_t *th)
|
|||
|
||||
if (catch_iseq != NULL) { /* found catch table */
|
||||
/* enter catch scope */
|
||||
rb_iseq_check(catch_iseq);
|
||||
cfp->sp = vm_base_ptr(cfp) + cont_sp;
|
||||
cfp->pc = cfp->iseq->body->iseq_encoded + cont_pc;
|
||||
|
||||
|
|
46
vm_core.h
46
vm_core.h
|
@ -257,10 +257,10 @@ struct rb_call_cache {
|
|||
#endif
|
||||
|
||||
typedef struct rb_iseq_location_struct {
|
||||
const VALUE path;
|
||||
const VALUE absolute_path;
|
||||
const VALUE base_label;
|
||||
const VALUE label;
|
||||
VALUE path;
|
||||
VALUE absolute_path;
|
||||
VALUE base_label;
|
||||
VALUE label;
|
||||
VALUE first_lineno; /* TODO: may be unsigned short */
|
||||
} rb_iseq_location_t;
|
||||
|
||||
|
@ -376,7 +376,7 @@ struct rb_iseq_constant_body {
|
|||
*/
|
||||
struct rb_call_cache *cc_entries; /* size is ci_size = ci_kw_size */
|
||||
|
||||
const VALUE mark_ary; /* Array: includes operands which should be GC marked */
|
||||
VALUE mark_ary; /* Array: includes operands which should be GC marked */
|
||||
|
||||
unsigned int local_table_size;
|
||||
unsigned int is_size;
|
||||
|
@ -389,12 +389,40 @@ struct rb_iseq_constant_body {
|
|||
/* typedef rb_iseq_t is in method.h */
|
||||
struct rb_iseq_struct {
|
||||
VALUE flags;
|
||||
struct iseq_compile_data *compile_data_; /* used at compile time */
|
||||
struct rb_iseq_constant_body *body;
|
||||
VALUE reserved1;
|
||||
VALUE reserved2;
|
||||
struct rb_iseq_constant_body *body;
|
||||
|
||||
union { /* 4, 5 words */
|
||||
struct iseq_compile_data *compile_data; /* used at compile time */
|
||||
|
||||
struct {
|
||||
VALUE obj;
|
||||
int index;
|
||||
} loader;
|
||||
} aux;
|
||||
};
|
||||
|
||||
#define USE_LAZY_LOAD 0
|
||||
|
||||
#ifndef USE_LAZY_LOAD
|
||||
#define USE_LAZY_LOAD
|
||||
#endif
|
||||
|
||||
#if USE_LAZY_LOAD
|
||||
const rb_iseq_t *rb_iseq_complete(const rb_iseq_t *iseq);
|
||||
|
||||
static inline const rb_iseq_t *
|
||||
rb_iseq_check(const rb_iseq_t *iseq)
|
||||
{
|
||||
if (iseq->body == NULL) {
|
||||
rb_iseq_complete((rb_iseq_t *)iseq);
|
||||
}
|
||||
return iseq;
|
||||
}
|
||||
#else
|
||||
#define rb_iseq_check(iseq) iseq
|
||||
#endif
|
||||
|
||||
enum ruby_special_exceptions {
|
||||
ruby_error_reenter,
|
||||
ruby_error_nomemory,
|
||||
|
@ -962,7 +990,7 @@ rb_block_t *rb_vm_control_frame_block_ptr(const rb_control_frame_t *cfp);
|
|||
(!RUBY_VM_VALID_CONTROL_FRAME_P((cfp), RUBY_VM_END_CONTROL_FRAME(th)))
|
||||
|
||||
#define RUBY_VM_IFUNC_P(ptr) (RB_TYPE_P((VALUE)(ptr), T_IMEMO) && imemo_type((VALUE)ptr) == imemo_ifunc)
|
||||
#define RUBY_VM_NORMAL_ISEQ_P(ptr) (RB_TYPE_P((VALUE)(ptr), T_IMEMO) && imemo_type((VALUE)ptr) == imemo_iseq)
|
||||
#define RUBY_VM_NORMAL_ISEQ_P(ptr) (RB_TYPE_P((VALUE)(ptr), T_IMEMO) && imemo_type((VALUE)ptr) == imemo_iseq && rb_iseq_check((rb_iseq_t *)ptr))
|
||||
|
||||
#define RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp) ((rb_block_t *)(&(cfp)->self))
|
||||
#define RUBY_VM_GET_CFP_FROM_BLOCK_PTR(b) \
|
||||
|
|
|
@ -1400,7 +1400,7 @@ def_iseq_ptr(rb_method_definition_t *def)
|
|||
#if VM_CHECK_MODE > 0
|
||||
if (def->type != VM_METHOD_TYPE_ISEQ) rb_bug("def_iseq_ptr: not iseq (%d)", def->type);
|
||||
#endif
|
||||
return def->body.iseq.iseqptr;
|
||||
return rb_iseq_check(def->body.iseq.iseqptr);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
|
@ -2428,15 +2428,14 @@ static VALUE
|
|||
vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, const struct rb_call_info *ci)
|
||||
{
|
||||
const rb_block_t *block = VM_CF_BLOCK_PTR(reg_cfp);
|
||||
const rb_iseq_t *iseq;
|
||||
VALUE type = GET_ISEQ()->body->local_iseq->body->type;
|
||||
|
||||
if ((type != ISEQ_TYPE_METHOD && type != ISEQ_TYPE_CLASS) || block == 0) {
|
||||
rb_vm_localjump_error("no block given (yield)", Qnil, 0);
|
||||
}
|
||||
iseq = block->iseq;
|
||||
|
||||
if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
|
||||
if (RUBY_VM_NORMAL_ISEQ_P(block->iseq)) {
|
||||
const rb_iseq_t *iseq = block->iseq;
|
||||
const int arg_size = iseq->body->param.size;
|
||||
int is_lambda = block_proc_is_lambda(block->proc);
|
||||
VALUE * const rsp = GET_SP() - calling->argc;
|
||||
|
|
Загрузка…
Ссылка в новой задаче