2000-05-01 13:42:38 +04:00
|
|
|
/**********************************************************************
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
class.c -
|
|
|
|
|
|
|
|
$Author$
|
|
|
|
created at: Tue Aug 10 15:05:44 JST 1993
|
|
|
|
|
* encoding.c: provide basic features for M17N.
* parse.y: encoding aware parsing.
* parse.y (pragma_encoding): encoding specification pragma.
* parse.y (rb_intern3): encoding specified symbols.
* string.c (rb_str_length): length based on characters.
for older behavior, bytesize method added.
* string.c (rb_str_index_m): index based on characters. rindex as
well.
* string.c (succ_char): encoding aware succeeding string.
* string.c (rb_str_reverse): reverse based on characters.
* string.c (rb_str_inspect): encoding aware string description.
* string.c (rb_str_upcase_bang): encoding aware case conversion.
downcase, capitalize, swapcase as well.
* string.c (rb_str_tr_bang): tr based on characters. delete,
squeeze, tr_s, count as well.
* string.c (rb_str_split_m): split based on characters.
* string.c (rb_str_each_line): encoding aware each_line.
* string.c (rb_str_each_char): added. iteration based on
characters.
* string.c (rb_str_strip_bang): encoding aware whitespace
stripping. lstrip, rstrip as well.
* string.c (rb_str_justify): encoding aware justifying (ljust,
rjust, center).
* string.c (str_encoding): get encoding attribute from a string.
* re.c (rb_reg_initialize): encoding aware regular expression
* sprintf.c (rb_str_format): formatting (i.e. length count) based
on characters.
* io.c (rb_io_getc): getc to return one-character string.
for older behavior, getbyte method added.
* ext/stringio/stringio.c (strio_getc): ditto.
* io.c (rb_io_ungetc): allow pushing arbitrary string at the
current reading point.
* ext/stringio/stringio.c (strio_ungetc): ditto.
* ext/strscan/strscan.c: encoding support.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13261 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-08-25 07:29:39 +04:00
|
|
|
Copyright (C) 1993-2007 Yukihiro Matsumoto
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2000-05-01 13:42:38 +04:00
|
|
|
**********************************************************************/
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2009-06-29 20:39:28 +04:00
|
|
|
/*!
|
2020-12-21 10:32:40 +03:00
|
|
|
* \addtogroup class
|
2009-06-29 20:39:28 +04:00
|
|
|
* \{
|
|
|
|
*/
|
|
|
|
|
2020-05-08 12:31:09 +03:00
|
|
|
#include "ruby/internal/config.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
#include "constant.h"
|
2021-06-01 20:34:06 +03:00
|
|
|
#include "debug_counter.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "id_table.h"
|
2014-11-15 14:49:06 +03:00
|
|
|
#include "internal.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "internal/class.h"
|
|
|
|
#include "internal/eval.h"
|
|
|
|
#include "internal/hash.h"
|
|
|
|
#include "internal/object.h"
|
2020-04-08 07:28:13 +03:00
|
|
|
#include "internal/string.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "internal/variable.h"
|
2007-06-10 07:06:15 +04:00
|
|
|
#include "ruby/st.h"
|
2009-07-15 18:59:41 +04:00
|
|
|
#include "vm_core.h"
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2013-05-02 11:54:17 +04:00
|
|
|
#define id_attached id__attached__
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2020-11-12 00:38:03 +03:00
|
|
|
#define METACLASS_OF(k) RBASIC(k)->klass
|
|
|
|
#define SET_METACLASS_OF(k, cls) RBASIC_SET_CLASS(k, cls)
|
|
|
|
|
2021-06-01 20:34:06 +03:00
|
|
|
RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state;
|
|
|
|
|
2021-11-16 00:09:10 +03:00
|
|
|
static rb_subclass_entry_t *
|
|
|
|
push_subclass_entry_to_list(VALUE super, VALUE klass)
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
{
|
|
|
|
rb_subclass_entry_t *entry, *head;
|
|
|
|
|
2021-11-16 00:09:10 +03:00
|
|
|
entry = ZALLOC(rb_subclass_entry_t);
|
|
|
|
entry->klass = klass;
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
|
2021-11-16 00:09:10 +03:00
|
|
|
head = RCLASS_SUBCLASSES(super);
|
|
|
|
if (!head) {
|
|
|
|
head = ZALLOC(rb_subclass_entry_t);
|
|
|
|
RCLASS_SUBCLASSES(super) = head;
|
|
|
|
}
|
|
|
|
entry->next = head->next;
|
|
|
|
entry->prev = head;
|
|
|
|
|
|
|
|
if (head->next) {
|
|
|
|
head->next->prev = entry;
|
|
|
|
}
|
|
|
|
head->next = entry;
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_class_subclass_add(VALUE super, VALUE klass)
|
|
|
|
{
|
|
|
|
if (super && super != Qundef) {
|
|
|
|
rb_subclass_entry_t *entry = push_subclass_entry_to_list(super, klass);
|
|
|
|
RCLASS_SUBCLASS_ENTRY(klass) = entry;
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
rb_module_add_to_subclasses_list(VALUE module, VALUE iclass)
|
|
|
|
{
|
2021-11-16 00:09:10 +03:00
|
|
|
rb_subclass_entry_t *entry = push_subclass_entry_to_list(module, iclass);
|
|
|
|
RCLASS_MODULE_SUBCLASS_ENTRY(iclass) = entry;
|
|
|
|
}
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
|
2021-11-16 00:09:10 +03:00
|
|
|
void
|
|
|
|
rb_class_remove_subclass_head(VALUE klass)
|
|
|
|
{
|
|
|
|
rb_subclass_entry_t *head = RCLASS_SUBCLASSES(klass);
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
|
|
|
|
if (head) {
|
2021-11-16 00:09:10 +03:00
|
|
|
if (head->next) {
|
|
|
|
head->next->prev = NULL;
|
|
|
|
}
|
|
|
|
RCLASS_SUBCLASSES(klass) = NULL;
|
|
|
|
xfree(head);
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_class_remove_from_super_subclasses(VALUE klass)
|
|
|
|
{
|
2021-11-16 00:09:10 +03:00
|
|
|
rb_subclass_entry_t *entry = RCLASS_SUBCLASS_ENTRY(klass);
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
|
2021-11-16 00:09:10 +03:00
|
|
|
if (entry) {
|
|
|
|
rb_subclass_entry_t *prev = entry->prev, *next = entry->next;
|
|
|
|
|
|
|
|
if (prev) {
|
|
|
|
prev->next = next;
|
|
|
|
}
|
|
|
|
if (next) {
|
|
|
|
next->prev = prev;
|
|
|
|
}
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
|
2014-03-09 09:22:01 +04:00
|
|
|
xfree(entry);
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
}
|
|
|
|
|
2021-11-16 00:09:10 +03:00
|
|
|
RCLASS_SUBCLASS_ENTRY(klass) = NULL;
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_class_remove_from_module_subclasses(VALUE klass)
|
|
|
|
{
|
2021-11-16 00:09:10 +03:00
|
|
|
rb_subclass_entry_t *entry = RCLASS_MODULE_SUBCLASS_ENTRY(klass);
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
|
2021-11-16 00:09:10 +03:00
|
|
|
if (entry) {
|
|
|
|
rb_subclass_entry_t *prev = entry->prev, *next = entry->next;
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
|
2021-11-16 00:09:10 +03:00
|
|
|
if (prev) {
|
|
|
|
prev->next = next;
|
|
|
|
}
|
2021-08-20 08:03:08 +03:00
|
|
|
if (next) {
|
2021-11-16 00:09:10 +03:00
|
|
|
next->prev = prev;
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
}
|
|
|
|
|
2014-03-09 09:22:01 +04:00
|
|
|
xfree(entry);
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
}
|
|
|
|
|
2021-11-16 00:09:10 +03:00
|
|
|
RCLASS_MODULE_SUBCLASS_ENTRY(klass) = NULL;
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-01-19 17:09:20 +03:00
|
|
|
rb_class_foreach_subclass(VALUE klass, void (*f)(VALUE, VALUE), VALUE arg)
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
{
|
2021-11-16 00:09:10 +03:00
|
|
|
// RCLASS_SUBCLASSES should always point to our head element which has NULL klass
|
2021-01-26 19:49:57 +03:00
|
|
|
rb_subclass_entry_t *cur = RCLASS_SUBCLASSES(klass);
|
2021-11-16 00:09:10 +03:00
|
|
|
// if we have a subclasses list, then the head is a placeholder with no valid
|
|
|
|
// class. So ignore it and use the next element in the list (if one exists)
|
|
|
|
if (cur) {
|
|
|
|
RUBY_ASSERT(!cur->klass);
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
|
|
|
|
/* do not be tempted to simplify this loop into a for loop, the order of
|
|
|
|
operations is important here if `f` modifies the linked list */
|
|
|
|
while (cur) {
|
|
|
|
VALUE curklass = cur->klass;
|
|
|
|
cur = cur->next;
|
2021-11-02 13:23:36 +03:00
|
|
|
// do not trigger GC during f, otherwise the cur will become
|
|
|
|
// a dangling pointer if the subclass is collected
|
2015-01-19 17:09:20 +03:00
|
|
|
f(curklass, arg);
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-19 17:09:20 +03:00
|
|
|
static void
|
|
|
|
class_detach_subclasses(VALUE klass, VALUE arg)
|
|
|
|
{
|
|
|
|
rb_class_remove_from_super_subclasses(klass);
|
|
|
|
}
|
|
|
|
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
void
|
|
|
|
rb_class_detach_subclasses(VALUE klass)
|
|
|
|
{
|
2015-01-19 17:09:20 +03:00
|
|
|
rb_class_foreach_subclass(klass, class_detach_subclasses, Qnil);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
class_detach_module_subclasses(VALUE klass, VALUE arg)
|
|
|
|
{
|
|
|
|
rb_class_remove_from_module_subclasses(klass);
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_class_detach_module_subclasses(VALUE klass)
|
|
|
|
{
|
2015-01-19 17:09:20 +03:00
|
|
|
rb_class_foreach_subclass(klass, class_detach_module_subclasses, Qnil);
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
}
|
|
|
|
|
2009-06-29 20:39:28 +04:00
|
|
|
/**
|
|
|
|
* Allocates a struct RClass for a new class.
|
|
|
|
*
|
|
|
|
* \param flags initial value for basic.flags of the returned class.
|
|
|
|
* \param klass the class of the returned class.
|
|
|
|
* \return an uninitialized Class object.
|
|
|
|
* \pre \p klass must refer \c Class class or an ancestor of Class.
|
|
|
|
* \pre \code (flags | T_CLASS) != 0 \endcode
|
|
|
|
* \post the returned class can safely be \c #initialize 'd.
|
|
|
|
*
|
|
|
|
* \note this function is not Class#allocate.
|
|
|
|
*/
|
2007-09-28 10:21:46 +04:00
|
|
|
static VALUE
|
|
|
|
class_alloc(VALUE flags, VALUE klass)
|
|
|
|
{
|
2021-08-02 21:22:47 +03:00
|
|
|
size_t alloc_size = sizeof(struct RClass);
|
2021-03-30 15:36:58 +03:00
|
|
|
|
|
|
|
#if USE_RVARGC
|
2021-08-02 21:22:47 +03:00
|
|
|
alloc_size += sizeof(rb_classext_t);
|
2021-03-30 15:36:58 +03:00
|
|
|
#endif
|
|
|
|
|
2021-12-22 07:13:20 +03:00
|
|
|
flags &= T_MASK;
|
|
|
|
flags |= FL_PROMOTED1 /* start from age == 2 */;
|
|
|
|
if (RGENGC_WB_PROTECTED_CLASS) flags |= FL_WB_PROTECTED;
|
|
|
|
RVARGC_NEWOBJ_OF(obj, struct RClass, klass, flags, alloc_size);
|
2021-03-30 15:36:58 +03:00
|
|
|
|
2021-11-19 22:51:58 +03:00
|
|
|
#if USE_RVARGC
|
|
|
|
memset(RCLASS_EXT(obj), 0, sizeof(rb_classext_t));
|
2022-01-14 21:59:38 +03:00
|
|
|
# if SIZEOF_SERIAL_T != SIZEOF_VALUE
|
|
|
|
RCLASS(obj)->class_serial_ptr = ZALLOC(rb_serial_t);
|
|
|
|
# endif
|
2021-11-19 22:51:58 +03:00
|
|
|
#else
|
2015-03-11 12:15:20 +03:00
|
|
|
obj->ptr = ZALLOC(rb_classext_t);
|
2021-03-30 15:36:58 +03:00
|
|
|
#endif
|
|
|
|
|
2015-03-11 12:15:20 +03:00
|
|
|
/* ZALLOC
|
|
|
|
RCLASS_IV_TBL(obj) = 0;
|
|
|
|
RCLASS_CONST_TBL(obj) = 0;
|
|
|
|
RCLASS_M_TBL(obj) = 0;
|
|
|
|
RCLASS_IV_INDEX_TBL(obj) = 0;
|
|
|
|
RCLASS_SET_SUPER((VALUE)obj, 0);
|
2021-01-26 19:49:57 +03:00
|
|
|
RCLASS_SUBCLASSES(obj) = NULL;
|
2021-01-26 19:06:31 +03:00
|
|
|
RCLASS_PARENT_SUBCLASSES(obj) = NULL;
|
2021-01-26 19:12:29 +03:00
|
|
|
RCLASS_MODULE_SUBCLASSES(obj) = NULL;
|
2015-03-11 12:15:20 +03:00
|
|
|
*/
|
|
|
|
RCLASS_SET_ORIGIN((VALUE)obj, (VALUE)obj);
|
2013-12-09 15:00:23 +04:00
|
|
|
RCLASS_SERIAL(obj) = rb_next_class_serial();
|
2019-07-22 11:44:58 +03:00
|
|
|
RB_OBJ_WRITE(obj, &RCLASS_REFINED_CLASS(obj), Qnil);
|
2021-01-26 19:29:09 +03:00
|
|
|
RCLASS_ALLOCATOR(obj) = 0;
|
2015-03-11 12:15:20 +03:00
|
|
|
|
2007-09-28 10:21:46 +04:00
|
|
|
return (VALUE)obj;
|
|
|
|
}
|
|
|
|
|
2015-08-12 11:43:55 +03:00
|
|
|
static void
|
|
|
|
RCLASS_M_TBL_INIT(VALUE c)
|
|
|
|
{
|
|
|
|
RCLASS_M_TBL(c) = rb_id_table_create(0);
|
|
|
|
}
|
2009-06-29 20:39:28 +04:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* A utility function that wraps class_alloc.
|
|
|
|
*
|
|
|
|
* allocates a class and initializes safely.
|
|
|
|
* \param super a class from which the new class derives.
|
|
|
|
* \return a class object.
|
|
|
|
* \pre \a super must be a class.
|
|
|
|
* \post the metaclass of the new class is Class.
|
|
|
|
*/
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_class_boot(VALUE super)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2007-09-28 10:21:46 +04:00
|
|
|
VALUE klass = class_alloc(T_CLASS, rb_cClass);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RCLASS_SET_SUPER(klass, super);
|
2013-12-03 12:11:07 +04:00
|
|
|
RCLASS_M_TBL_INIT(klass);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
return (VALUE)klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2022-02-27 03:05:06 +03:00
|
|
|
static VALUE *
|
|
|
|
class_superclasses_including_self(VALUE klass)
|
2022-01-26 06:16:57 +03:00
|
|
|
{
|
2022-02-27 03:05:06 +03:00
|
|
|
if (FL_TEST_RAW(klass, RCLASS_SUPERCLASSES_INCLUDE_SELF))
|
|
|
|
return RCLASS_SUPERCLASSES(klass);
|
2022-01-26 06:16:57 +03:00
|
|
|
|
2022-02-27 03:05:06 +03:00
|
|
|
size_t depth = RCLASS_SUPERCLASS_DEPTH(klass);
|
|
|
|
VALUE *superclasses = xmalloc(sizeof(VALUE) * (depth + 1));
|
|
|
|
if (depth > 0)
|
|
|
|
memcpy(superclasses, RCLASS_SUPERCLASSES(klass), sizeof(VALUE) * depth);
|
|
|
|
superclasses[depth] = klass;
|
2022-01-26 06:16:57 +03:00
|
|
|
|
2022-02-27 03:05:06 +03:00
|
|
|
RCLASS_SUPERCLASSES(klass) = superclasses;
|
|
|
|
FL_SET_RAW(klass, RCLASS_SUPERCLASSES_INCLUDE_SELF);
|
|
|
|
return superclasses;
|
2022-01-26 06:16:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_class_update_superclasses(VALUE klass)
|
|
|
|
{
|
|
|
|
VALUE super = RCLASS_SUPER(klass);
|
|
|
|
|
|
|
|
if (!RB_TYPE_P(klass, T_CLASS)) return;
|
|
|
|
if (super == Qundef) return;
|
|
|
|
|
|
|
|
// If the superclass array is already built
|
|
|
|
if (RCLASS_SUPERCLASSES(klass))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// find the proper superclass
|
|
|
|
while (super != Qfalse && !RB_TYPE_P(super, T_CLASS)) {
|
|
|
|
super = RCLASS_SUPER(super);
|
|
|
|
}
|
|
|
|
|
|
|
|
// For BasicObject and uninitialized classes, depth=0 and ary=NULL
|
|
|
|
if (super == Qfalse)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Sometimes superclasses are set before the full ancestry tree is built
|
|
|
|
// This happens during metaclass construction
|
|
|
|
if (super != rb_cBasicObject && !RCLASS_SUPERCLASS_DEPTH(super)) {
|
|
|
|
rb_class_update_superclasses(super);
|
|
|
|
|
|
|
|
// If it is still unset we need to try later
|
|
|
|
if (!RCLASS_SUPERCLASS_DEPTH(super))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-02-27 03:05:06 +03:00
|
|
|
RCLASS_SUPERCLASSES(klass) = class_superclasses_including_self(super);
|
|
|
|
RCLASS_SUPERCLASS_DEPTH(klass) = RCLASS_SUPERCLASS_DEPTH(super) + 1;
|
2022-01-26 06:16:57 +03:00
|
|
|
}
|
|
|
|
|
2004-11-16 07:55:14 +03:00
|
|
|
void
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_check_inheritable(VALUE super)
|
2004-11-16 07:55:14 +03:00
|
|
|
{
|
2011-09-29 15:07:45 +04:00
|
|
|
if (!RB_TYPE_P(super, T_CLASS)) {
|
2020-07-18 18:18:39 +03:00
|
|
|
rb_raise(rb_eTypeError, "superclass must be an instance of Class (given an instance of %"PRIsVALUE")",
|
2015-06-28 06:28:50 +03:00
|
|
|
rb_obj_class(super));
|
2004-11-16 07:55:14 +03:00
|
|
|
}
|
|
|
|
if (RBASIC(super)->flags & FL_SINGLETON) {
|
|
|
|
rb_raise(rb_eTypeError, "can't make subclass of singleton class");
|
|
|
|
}
|
2009-10-24 03:37:14 +04:00
|
|
|
if (super == rb_cClass) {
|
|
|
|
rb_raise(rb_eTypeError, "can't make subclass of Class");
|
|
|
|
}
|
2004-11-16 07:55:14 +03:00
|
|
|
}
|
|
|
|
|
2001-07-18 09:56:05 +04:00
|
|
|
VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_class_new(VALUE super)
|
2001-07-18 09:56:05 +04:00
|
|
|
{
|
|
|
|
Check_Type(super, T_CLASS);
|
2004-11-16 07:55:14 +03:00
|
|
|
rb_check_inheritable(super);
|
2001-07-18 09:56:05 +04:00
|
|
|
return rb_class_boot(super);
|
|
|
|
}
|
|
|
|
|
2020-07-26 05:52:19 +03:00
|
|
|
VALUE
|
|
|
|
rb_class_s_alloc(VALUE klass)
|
|
|
|
{
|
|
|
|
return rb_class_boot(0);
|
|
|
|
}
|
|
|
|
|
2011-05-31 20:16:06 +04:00
|
|
|
static void
|
2015-06-03 22:36:52 +03:00
|
|
|
clone_method(VALUE old_klass, VALUE new_klass, ID mid, const rb_method_entry_t *me)
|
2009-07-15 18:59:41 +04:00
|
|
|
{
|
2015-06-03 14:10:16 +03:00
|
|
|
if (me->def->type == VM_METHOD_TYPE_ISEQ) {
|
|
|
|
rb_cref_t *new_cref;
|
2015-06-03 22:36:52 +03:00
|
|
|
rb_vm_rewrite_cref(me->def->body.iseq.cref, old_klass, new_klass, &new_cref);
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_add_method_iseq(new_klass, mid, me->def->body.iseq.iseqptr, new_cref, METHOD_ENTRY_VISI(me));
|
2009-08-28 06:45:41 +04:00
|
|
|
}
|
|
|
|
else {
|
2015-06-06 13:19:48 +03:00
|
|
|
rb_method_entry_set(new_klass, mid, me, METHOD_ENTRY_VISI(me));
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2011-05-31 20:16:06 +04:00
|
|
|
}
|
|
|
|
|
2015-06-03 22:36:52 +03:00
|
|
|
struct clone_method_arg {
|
|
|
|
VALUE new_klass;
|
|
|
|
VALUE old_klass;
|
|
|
|
};
|
|
|
|
|
2015-08-12 11:43:55 +03:00
|
|
|
static enum rb_id_table_iterator_result
|
|
|
|
clone_method_i(ID key, VALUE value, void *data)
|
2011-05-31 20:16:06 +04:00
|
|
|
{
|
2015-06-03 22:36:52 +03:00
|
|
|
const struct clone_method_arg *arg = (struct clone_method_arg *)data;
|
2015-08-12 11:43:55 +03:00
|
|
|
clone_method(arg->old_klass, arg->new_klass, key, (const rb_method_entry_t *)value);
|
2015-08-12 11:59:27 +03:00
|
|
|
return ID_TABLE_CONTINUE;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2013-06-14 13:23:54 +04:00
|
|
|
struct clone_const_arg {
|
|
|
|
VALUE klass;
|
use id_table for constant tables
valgrind 3.9.0 on x86-64 reports a minor reduction in memory usage
when loading only RubyGems and RDoc by running: ruby -rrdoc -eexit
before: HEAP SUMMARY:
in use at exit: 2,913,448 bytes in 27,394 blocks
total heap usage: 48,362 allocs, 20,968 frees, 9,034,621 bytes alloc
after: HEAP SUMMARY:
in use at exit: 2,880,056 bytes in 26,712 blocks
total heap usage: 47,791 allocs, 21,079 frees, 9,046,507 bytes alloc
* class.c (struct clone_const_arg): adjust for id_table
(clone_const): ditto
(clone_const_i): ditto
(rb_mod_init_copy): ditto
(rb_singleton_class_clone_and_attach): ditto
(rb_include_class_new): ditto
(include_modules_at): ditto
* constant.h (rb_free_const_table): ditto
* gc.c (free_const_entry_i): ditto
(rb_free_const_table): ditto
(obj_memsize_of): ditto
(mark_const_entry_i): ditto
(mark_const_tbl): ditto
* internal.h (struct rb_classext_struct): ditto
* object.c (rb_mod_const_set): resolve class name on assignment
* variable.c (const_update): replace with const_tbl_update
(const_tbl_update): new function
(fc_i): adjust for id_table
(find_class_path): ditto
(autoload_const_set): st_update => const_tbl_update
(rb_const_remove): adjust for id_table
(sv_i): ditto
(rb_local_constants_i): ditto
(rb_local_constants): ditto
(rb_mod_const_at): ditto
(rb_mod_const_set): ditto
(rb_const_lookup): ditto
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53376 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-12-29 23:19:14 +03:00
|
|
|
struct rb_id_table *tbl;
|
2013-06-14 13:23:54 +04:00
|
|
|
};
|
|
|
|
|
2010-10-26 21:27:32 +04:00
|
|
|
static int
|
2013-06-14 13:23:54 +04:00
|
|
|
clone_const(ID key, const rb_const_entry_t *ce, struct clone_const_arg *arg)
|
2010-10-26 21:27:32 +04:00
|
|
|
{
|
|
|
|
rb_const_entry_t *nce = ALLOC(rb_const_entry_t);
|
2013-06-14 13:23:54 +04:00
|
|
|
MEMCPY(nce, ce, rb_const_entry_t, 1);
|
* include/ruby/ruby.h: rename OBJ_WRITE and OBJ_WRITTEN into
RB_OBJ_WRITE and RB_OBJ_WRITTEN.
* array.c, class.c, compile.c, hash.c, internal.h, iseq.c,
proc.c, process.c, re.c, string.c, variable.c, vm.c,
vm_eval.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: catch up this change.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44299 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-12-20 12:07:47 +04:00
|
|
|
RB_OBJ_WRITTEN(arg->klass, Qundef, ce->value);
|
|
|
|
RB_OBJ_WRITTEN(arg->klass, Qundef, ce->file);
|
2013-06-14 13:23:54 +04:00
|
|
|
|
use id_table for constant tables
valgrind 3.9.0 on x86-64 reports a minor reduction in memory usage
when loading only RubyGems and RDoc by running: ruby -rrdoc -eexit
before: HEAP SUMMARY:
in use at exit: 2,913,448 bytes in 27,394 blocks
total heap usage: 48,362 allocs, 20,968 frees, 9,034,621 bytes alloc
after: HEAP SUMMARY:
in use at exit: 2,880,056 bytes in 26,712 blocks
total heap usage: 47,791 allocs, 21,079 frees, 9,046,507 bytes alloc
* class.c (struct clone_const_arg): adjust for id_table
(clone_const): ditto
(clone_const_i): ditto
(rb_mod_init_copy): ditto
(rb_singleton_class_clone_and_attach): ditto
(rb_include_class_new): ditto
(include_modules_at): ditto
* constant.h (rb_free_const_table): ditto
* gc.c (free_const_entry_i): ditto
(rb_free_const_table): ditto
(obj_memsize_of): ditto
(mark_const_entry_i): ditto
(mark_const_tbl): ditto
* internal.h (struct rb_classext_struct): ditto
* object.c (rb_mod_const_set): resolve class name on assignment
* variable.c (const_update): replace with const_tbl_update
(const_tbl_update): new function
(fc_i): adjust for id_table
(find_class_path): ditto
(autoload_const_set): st_update => const_tbl_update
(rb_const_remove): adjust for id_table
(sv_i): ditto
(rb_local_constants_i): ditto
(rb_local_constants): ditto
(rb_mod_const_at): ditto
(rb_mod_const_set): ditto
(rb_const_lookup): ditto
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53376 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-12-29 23:19:14 +03:00
|
|
|
rb_id_table_insert(arg->tbl, key, (VALUE)nce);
|
|
|
|
return ID_TABLE_CONTINUE;
|
2010-10-26 21:27:32 +04:00
|
|
|
}
|
|
|
|
|
use id_table for constant tables
valgrind 3.9.0 on x86-64 reports a minor reduction in memory usage
when loading only RubyGems and RDoc by running: ruby -rrdoc -eexit
before: HEAP SUMMARY:
in use at exit: 2,913,448 bytes in 27,394 blocks
total heap usage: 48,362 allocs, 20,968 frees, 9,034,621 bytes alloc
after: HEAP SUMMARY:
in use at exit: 2,880,056 bytes in 26,712 blocks
total heap usage: 47,791 allocs, 21,079 frees, 9,046,507 bytes alloc
* class.c (struct clone_const_arg): adjust for id_table
(clone_const): ditto
(clone_const_i): ditto
(rb_mod_init_copy): ditto
(rb_singleton_class_clone_and_attach): ditto
(rb_include_class_new): ditto
(include_modules_at): ditto
* constant.h (rb_free_const_table): ditto
* gc.c (free_const_entry_i): ditto
(rb_free_const_table): ditto
(obj_memsize_of): ditto
(mark_const_entry_i): ditto
(mark_const_tbl): ditto
* internal.h (struct rb_classext_struct): ditto
* object.c (rb_mod_const_set): resolve class name on assignment
* variable.c (const_update): replace with const_tbl_update
(const_tbl_update): new function
(fc_i): adjust for id_table
(find_class_path): ditto
(autoload_const_set): st_update => const_tbl_update
(rb_const_remove): adjust for id_table
(sv_i): ditto
(rb_local_constants_i): ditto
(rb_local_constants): ditto
(rb_mod_const_at): ditto
(rb_mod_const_set): ditto
(rb_const_lookup): ditto
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53376 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-12-29 23:19:14 +03:00
|
|
|
static enum rb_id_table_iterator_result
|
|
|
|
clone_const_i(ID key, VALUE value, void *data)
|
2011-06-04 07:49:50 +04:00
|
|
|
{
|
use id_table for constant tables
valgrind 3.9.0 on x86-64 reports a minor reduction in memory usage
when loading only RubyGems and RDoc by running: ruby -rrdoc -eexit
before: HEAP SUMMARY:
in use at exit: 2,913,448 bytes in 27,394 blocks
total heap usage: 48,362 allocs, 20,968 frees, 9,034,621 bytes alloc
after: HEAP SUMMARY:
in use at exit: 2,880,056 bytes in 26,712 blocks
total heap usage: 47,791 allocs, 21,079 frees, 9,046,507 bytes alloc
* class.c (struct clone_const_arg): adjust for id_table
(clone_const): ditto
(clone_const_i): ditto
(rb_mod_init_copy): ditto
(rb_singleton_class_clone_and_attach): ditto
(rb_include_class_new): ditto
(include_modules_at): ditto
* constant.h (rb_free_const_table): ditto
* gc.c (free_const_entry_i): ditto
(rb_free_const_table): ditto
(obj_memsize_of): ditto
(mark_const_entry_i): ditto
(mark_const_tbl): ditto
* internal.h (struct rb_classext_struct): ditto
* object.c (rb_mod_const_set): resolve class name on assignment
* variable.c (const_update): replace with const_tbl_update
(const_tbl_update): new function
(fc_i): adjust for id_table
(find_class_path): ditto
(autoload_const_set): st_update => const_tbl_update
(rb_const_remove): adjust for id_table
(sv_i): ditto
(rb_local_constants_i): ditto
(rb_local_constants): ditto
(rb_mod_const_at): ditto
(rb_mod_const_set): ditto
(rb_const_lookup): ditto
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53376 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-12-29 23:19:14 +03:00
|
|
|
return clone_const(key, (const rb_const_entry_t *)value, data);
|
2011-06-04 07:49:50 +04:00
|
|
|
}
|
|
|
|
|
2012-12-13 18:11:01 +04:00
|
|
|
static void
|
|
|
|
class_init_copy_check(VALUE clone, VALUE orig)
|
|
|
|
{
|
|
|
|
if (orig == rb_cBasicObject) {
|
|
|
|
rb_raise(rb_eTypeError, "can't copy the root class");
|
|
|
|
}
|
|
|
|
if (RCLASS_SUPER(clone) != 0 || clone == rb_cBasicObject) {
|
|
|
|
rb_raise(rb_eTypeError, "already initialized class");
|
|
|
|
}
|
|
|
|
if (FL_TEST(orig, FL_SINGLETON)) {
|
|
|
|
rb_raise(rb_eTypeError, "can't copy singleton class");
|
|
|
|
}
|
|
|
|
}
|
2019-08-09 07:08:01 +03:00
|
|
|
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
static void
|
|
|
|
copy_tables(VALUE clone, VALUE orig)
|
2001-05-02 08:22:21 +04:00
|
|
|
{
|
2014-05-08 09:34:31 +04:00
|
|
|
if (RCLASS_IV_TBL(clone)) {
|
|
|
|
st_free_table(RCLASS_IV_TBL(clone));
|
|
|
|
RCLASS_IV_TBL(clone) = 0;
|
|
|
|
}
|
|
|
|
if (RCLASS_CONST_TBL(clone)) {
|
|
|
|
rb_free_const_table(RCLASS_CONST_TBL(clone));
|
|
|
|
RCLASS_CONST_TBL(clone) = 0;
|
|
|
|
}
|
2015-03-06 01:20:14 +03:00
|
|
|
RCLASS_M_TBL(clone) = 0;
|
2007-09-28 10:21:46 +04:00
|
|
|
if (RCLASS_IV_TBL(orig)) {
|
2010-10-14 02:22:18 +04:00
|
|
|
st_data_t id;
|
2001-10-22 10:48:18 +04:00
|
|
|
|
2019-09-22 10:21:26 +03:00
|
|
|
rb_iv_tbl_copy(clone, orig);
|
2012-05-23 00:15:28 +04:00
|
|
|
CONST_ID(id, "__tmp_classpath__");
|
|
|
|
st_delete(RCLASS_IV_TBL(clone), &id, 0);
|
2008-06-09 13:25:32 +04:00
|
|
|
CONST_ID(id, "__classpath__");
|
2010-10-14 02:22:18 +04:00
|
|
|
st_delete(RCLASS_IV_TBL(clone), &id, 0);
|
2008-06-09 13:25:32 +04:00
|
|
|
CONST_ID(id, "__classid__");
|
2010-10-14 02:22:18 +04:00
|
|
|
st_delete(RCLASS_IV_TBL(clone), &id, 0);
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
2010-10-26 21:27:21 +04:00
|
|
|
if (RCLASS_CONST_TBL(orig)) {
|
2013-06-14 13:23:54 +04:00
|
|
|
struct clone_const_arg arg;
|
2014-05-08 09:34:31 +04:00
|
|
|
|
use id_table for constant tables
valgrind 3.9.0 on x86-64 reports a minor reduction in memory usage
when loading only RubyGems and RDoc by running: ruby -rrdoc -eexit
before: HEAP SUMMARY:
in use at exit: 2,913,448 bytes in 27,394 blocks
total heap usage: 48,362 allocs, 20,968 frees, 9,034,621 bytes alloc
after: HEAP SUMMARY:
in use at exit: 2,880,056 bytes in 26,712 blocks
total heap usage: 47,791 allocs, 21,079 frees, 9,046,507 bytes alloc
* class.c (struct clone_const_arg): adjust for id_table
(clone_const): ditto
(clone_const_i): ditto
(rb_mod_init_copy): ditto
(rb_singleton_class_clone_and_attach): ditto
(rb_include_class_new): ditto
(include_modules_at): ditto
* constant.h (rb_free_const_table): ditto
* gc.c (free_const_entry_i): ditto
(rb_free_const_table): ditto
(obj_memsize_of): ditto
(mark_const_entry_i): ditto
(mark_const_tbl): ditto
* internal.h (struct rb_classext_struct): ditto
* object.c (rb_mod_const_set): resolve class name on assignment
* variable.c (const_update): replace with const_tbl_update
(const_tbl_update): new function
(fc_i): adjust for id_table
(find_class_path): ditto
(autoload_const_set): st_update => const_tbl_update
(rb_const_remove): adjust for id_table
(sv_i): ditto
(rb_local_constants_i): ditto
(rb_local_constants): ditto
(rb_mod_const_at): ditto
(rb_mod_const_set): ditto
(rb_const_lookup): ditto
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53376 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-12-29 23:19:14 +03:00
|
|
|
arg.tbl = RCLASS_CONST_TBL(clone) = rb_id_table_create(0);
|
2013-06-14 13:23:54 +04:00
|
|
|
arg.klass = clone;
|
use id_table for constant tables
valgrind 3.9.0 on x86-64 reports a minor reduction in memory usage
when loading only RubyGems and RDoc by running: ruby -rrdoc -eexit
before: HEAP SUMMARY:
in use at exit: 2,913,448 bytes in 27,394 blocks
total heap usage: 48,362 allocs, 20,968 frees, 9,034,621 bytes alloc
after: HEAP SUMMARY:
in use at exit: 2,880,056 bytes in 26,712 blocks
total heap usage: 47,791 allocs, 21,079 frees, 9,046,507 bytes alloc
* class.c (struct clone_const_arg): adjust for id_table
(clone_const): ditto
(clone_const_i): ditto
(rb_mod_init_copy): ditto
(rb_singleton_class_clone_and_attach): ditto
(rb_include_class_new): ditto
(include_modules_at): ditto
* constant.h (rb_free_const_table): ditto
* gc.c (free_const_entry_i): ditto
(rb_free_const_table): ditto
(obj_memsize_of): ditto
(mark_const_entry_i): ditto
(mark_const_tbl): ditto
* internal.h (struct rb_classext_struct): ditto
* object.c (rb_mod_const_set): resolve class name on assignment
* variable.c (const_update): replace with const_tbl_update
(const_tbl_update): new function
(fc_i): adjust for id_table
(find_class_path): ditto
(autoload_const_set): st_update => const_tbl_update
(rb_const_remove): adjust for id_table
(sv_i): ditto
(rb_local_constants_i): ditto
(rb_local_constants): ditto
(rb_mod_const_at): ditto
(rb_mod_const_set): ditto
(rb_const_lookup): ditto
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53376 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-12-29 23:19:14 +03:00
|
|
|
rb_id_table_foreach(RCLASS_CONST_TBL(orig), clone_const_i, &arg);
|
2010-10-26 21:27:21 +04:00
|
|
|
}
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
}
|
|
|
|
|
2021-02-13 06:45:08 +03:00
|
|
|
static bool ensure_origin(VALUE klass);
|
2020-07-23 00:27:03 +03:00
|
|
|
|
2021-09-23 19:30:00 +03:00
|
|
|
/**
|
|
|
|
* If this flag is set, that module is allocated but not initialized yet.
|
|
|
|
*/
|
|
|
|
enum {RMODULE_ALLOCATED_BUT_NOT_INITIALIZED = RUBY_FL_USER5};
|
|
|
|
|
2020-07-26 05:52:19 +03:00
|
|
|
static inline bool
|
|
|
|
RMODULE_UNINITIALIZED(VALUE module)
|
|
|
|
{
|
2021-09-23 19:30:00 +03:00
|
|
|
return FL_TEST_RAW(module, RMODULE_ALLOCATED_BUT_NOT_INITIALIZED);
|
2020-07-26 05:52:19 +03:00
|
|
|
}
|
|
|
|
|
2021-09-23 18:55:11 +03:00
|
|
|
void
|
|
|
|
rb_module_set_initialized(VALUE mod)
|
|
|
|
{
|
2021-09-23 19:30:00 +03:00
|
|
|
FL_UNSET_RAW(mod, RMODULE_ALLOCATED_BUT_NOT_INITIALIZED);
|
|
|
|
/* no more re-initialization */
|
2021-09-23 18:55:11 +03:00
|
|
|
}
|
|
|
|
|
2020-07-26 05:52:19 +03:00
|
|
|
void
|
2021-09-19 16:39:18 +03:00
|
|
|
rb_module_check_initializable(VALUE mod)
|
2020-07-26 05:52:19 +03:00
|
|
|
{
|
|
|
|
if (!RMODULE_UNINITIALIZED(mod)) {
|
|
|
|
rb_raise(rb_eTypeError, "already initialized module");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
/* :nodoc: */
|
|
|
|
VALUE
|
|
|
|
rb_mod_init_copy(VALUE clone, VALUE orig)
|
|
|
|
{
|
2020-07-26 05:52:19 +03:00
|
|
|
switch (BUILTIN_TYPE(clone)) {
|
|
|
|
case T_CLASS:
|
|
|
|
case T_ICLASS:
|
2020-07-29 20:28:46 +03:00
|
|
|
class_init_copy_check(clone, orig);
|
2020-07-26 05:52:19 +03:00
|
|
|
break;
|
|
|
|
case T_MODULE:
|
2021-09-19 16:39:18 +03:00
|
|
|
rb_module_check_initializable(clone);
|
2020-07-26 05:52:19 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2020-07-29 20:28:46 +03:00
|
|
|
}
|
|
|
|
if (!OBJ_INIT_COPY(clone, orig)) return clone;
|
|
|
|
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
/* cloned flag is refer at constant inline cache
|
|
|
|
* see vm_get_const_key_cref() in vm_insnhelper.c
|
|
|
|
*/
|
|
|
|
FL_SET(clone, RCLASS_CLONED);
|
|
|
|
FL_SET(orig , RCLASS_CLONED);
|
|
|
|
|
|
|
|
if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) {
|
|
|
|
RBASIC_SET_CLASS(clone, rb_singleton_class_clone(orig));
|
2022-02-19 15:33:53 +03:00
|
|
|
rb_singleton_class_attached(METACLASS_OF(clone), (VALUE)clone);
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
}
|
2021-01-26 19:29:09 +03:00
|
|
|
RCLASS_ALLOCATOR(clone) = RCLASS_ALLOCATOR(orig);
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
copy_tables(clone, orig);
|
2007-09-28 10:21:46 +04:00
|
|
|
if (RCLASS_M_TBL(orig)) {
|
2015-06-03 22:36:52 +03:00
|
|
|
struct clone_method_arg arg;
|
|
|
|
arg.old_klass = orig;
|
|
|
|
arg.new_klass = clone;
|
2013-12-03 12:11:07 +04:00
|
|
|
RCLASS_M_TBL_INIT(clone);
|
2015-08-12 11:43:55 +03:00
|
|
|
rb_id_table_foreach(RCLASS_M_TBL(orig), clone_method_i, &arg);
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
|
|
|
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
if (RCLASS_ORIGIN(orig) == orig) {
|
|
|
|
RCLASS_SET_SUPER(clone, RCLASS_SUPER(orig));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
VALUE p = RCLASS_SUPER(orig);
|
|
|
|
VALUE orig_origin = RCLASS_ORIGIN(orig);
|
|
|
|
VALUE prev_clone_p = clone;
|
|
|
|
VALUE origin_stack = rb_ary_tmp_new(2);
|
|
|
|
VALUE origin[2];
|
|
|
|
VALUE clone_p = 0;
|
|
|
|
long origin_len;
|
|
|
|
int add_subclass;
|
|
|
|
VALUE clone_origin;
|
|
|
|
|
2020-07-23 00:27:03 +03:00
|
|
|
ensure_origin(clone);
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
clone_origin = RCLASS_ORIGIN(clone);
|
|
|
|
|
|
|
|
while (p && p != orig_origin) {
|
|
|
|
if (BUILTIN_TYPE(p) != T_ICLASS) {
|
|
|
|
rb_bug("non iclass between module/class and origin");
|
|
|
|
}
|
2022-02-19 15:33:53 +03:00
|
|
|
clone_p = class_alloc(RBASIC(p)->flags, METACLASS_OF(p));
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
RCLASS_SET_SUPER(prev_clone_p, clone_p);
|
|
|
|
prev_clone_p = clone_p;
|
|
|
|
RCLASS_M_TBL(clone_p) = RCLASS_M_TBL(p);
|
|
|
|
RCLASS_CONST_TBL(clone_p) = RCLASS_CONST_TBL(p);
|
|
|
|
RCLASS_IV_TBL(clone_p) = RCLASS_IV_TBL(p);
|
2021-01-26 19:29:09 +03:00
|
|
|
RCLASS_ALLOCATOR(clone_p) = RCLASS_ALLOCATOR(p);
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
if (RB_TYPE_P(clone, T_CLASS)) {
|
|
|
|
RCLASS_SET_INCLUDER(clone_p, clone);
|
|
|
|
}
|
|
|
|
add_subclass = TRUE;
|
|
|
|
if (p != RCLASS_ORIGIN(p)) {
|
|
|
|
origin[0] = clone_p;
|
|
|
|
origin[1] = RCLASS_ORIGIN(p);
|
|
|
|
rb_ary_cat(origin_stack, origin, 2);
|
|
|
|
}
|
|
|
|
else if ((origin_len = RARRAY_LEN(origin_stack)) > 1 &&
|
|
|
|
RARRAY_AREF(origin_stack, origin_len - 1) == p) {
|
|
|
|
RCLASS_SET_ORIGIN(RARRAY_AREF(origin_stack, (origin_len -= 2)), clone_p);
|
|
|
|
RICLASS_SET_ORIGIN_SHARED_MTBL(clone_p);
|
|
|
|
rb_ary_resize(origin_stack, origin_len);
|
|
|
|
add_subclass = FALSE;
|
|
|
|
}
|
|
|
|
if (add_subclass) {
|
2022-02-19 15:33:53 +03:00
|
|
|
rb_module_add_to_subclasses_list(METACLASS_OF(p), clone_p);
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
}
|
|
|
|
p = RCLASS_SUPER(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p == orig_origin) {
|
|
|
|
if (clone_p) {
|
|
|
|
RCLASS_SET_SUPER(clone_p, clone_origin);
|
|
|
|
RCLASS_SET_SUPER(clone_origin, RCLASS_SUPER(orig_origin));
|
|
|
|
}
|
|
|
|
copy_tables(clone_origin, orig_origin);
|
|
|
|
if (RCLASS_M_TBL(orig_origin)) {
|
|
|
|
struct clone_method_arg arg;
|
|
|
|
arg.old_klass = orig;
|
|
|
|
arg.new_klass = clone;
|
|
|
|
RCLASS_M_TBL_INIT(clone_origin);
|
|
|
|
rb_id_table_foreach(RCLASS_M_TBL(orig_origin), clone_method_i, &arg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_bug("no origin for class that has origin");
|
|
|
|
}
|
2022-04-16 01:21:10 +03:00
|
|
|
|
|
|
|
rb_class_update_superclasses(clone);
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
}
|
|
|
|
|
2003-08-07 01:50:06 +04:00
|
|
|
return clone;
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_singleton_class_clone(VALUE obj)
|
2012-12-29 06:37:47 +04:00
|
|
|
{
|
|
|
|
return rb_singleton_class_clone_and_attach(obj, Qundef);
|
|
|
|
}
|
|
|
|
|
2020-11-12 00:38:03 +03:00
|
|
|
// Clone and return the singleton class of `obj` if it has been created and is attached to `obj`.
|
2012-12-29 06:37:47 +04:00
|
|
|
VALUE
|
|
|
|
rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
|
2001-05-02 08:22:21 +04:00
|
|
|
{
|
2022-02-19 15:33:53 +03:00
|
|
|
const VALUE klass = METACLASS_OF(obj);
|
2001-05-02 08:22:21 +04:00
|
|
|
|
2020-11-12 00:38:03 +03:00
|
|
|
// Note that `rb_singleton_class()` can create situations where `klass` is
|
|
|
|
// attached to an object other than `obj`. In which case `obj` does not have
|
|
|
|
// a material singleton class attached yet and there is no singleton class
|
|
|
|
// to clone.
|
|
|
|
if (!(FL_TEST(klass, FL_SINGLETON) && rb_attr_get(klass, id_attached) == obj)) {
|
|
|
|
// nothing to clone
|
|
|
|
return klass;
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
else {
|
|
|
|
/* copy singleton(unnamed) class */
|
2020-11-12 00:38:03 +03:00
|
|
|
bool klass_of_clone_is_new;
|
2012-01-07 18:02:23 +04:00
|
|
|
VALUE clone = class_alloc(RBASIC(klass)->flags, 0);
|
2002-09-03 09:20:14 +04:00
|
|
|
|
|
|
|
if (BUILTIN_TYPE(obj) == T_CLASS) {
|
2020-11-12 00:38:03 +03:00
|
|
|
klass_of_clone_is_new = true;
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RBASIC_SET_CLASS(clone, clone);
|
2002-09-03 09:20:14 +04:00
|
|
|
}
|
|
|
|
else {
|
2020-11-12 00:38:03 +03:00
|
|
|
VALUE klass_metaclass_clone = rb_singleton_class_clone(klass);
|
|
|
|
// When `METACLASS_OF(klass) == klass_metaclass_clone`, it means the
|
|
|
|
// recursive call did not clone `METACLASS_OF(klass)`.
|
|
|
|
klass_of_clone_is_new = (METACLASS_OF(klass) != klass_metaclass_clone);
|
|
|
|
RBASIC_SET_CLASS(clone, klass_metaclass_clone);
|
2002-09-03 09:20:14 +04:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RCLASS_SET_SUPER(clone, RCLASS_SUPER(klass));
|
2021-01-26 19:29:09 +03:00
|
|
|
RCLASS_ALLOCATOR(clone) = RCLASS_ALLOCATOR(klass);
|
2007-09-28 10:21:46 +04:00
|
|
|
if (RCLASS_IV_TBL(klass)) {
|
2019-09-22 10:21:26 +03:00
|
|
|
rb_iv_tbl_copy(clone, klass);
|
2001-03-28 12:43:25 +04:00
|
|
|
}
|
2010-10-26 21:27:21 +04:00
|
|
|
if (RCLASS_CONST_TBL(klass)) {
|
2013-06-14 13:23:54 +04:00
|
|
|
struct clone_const_arg arg;
|
use id_table for constant tables
valgrind 3.9.0 on x86-64 reports a minor reduction in memory usage
when loading only RubyGems and RDoc by running: ruby -rrdoc -eexit
before: HEAP SUMMARY:
in use at exit: 2,913,448 bytes in 27,394 blocks
total heap usage: 48,362 allocs, 20,968 frees, 9,034,621 bytes alloc
after: HEAP SUMMARY:
in use at exit: 2,880,056 bytes in 26,712 blocks
total heap usage: 47,791 allocs, 21,079 frees, 9,046,507 bytes alloc
* class.c (struct clone_const_arg): adjust for id_table
(clone_const): ditto
(clone_const_i): ditto
(rb_mod_init_copy): ditto
(rb_singleton_class_clone_and_attach): ditto
(rb_include_class_new): ditto
(include_modules_at): ditto
* constant.h (rb_free_const_table): ditto
* gc.c (free_const_entry_i): ditto
(rb_free_const_table): ditto
(obj_memsize_of): ditto
(mark_const_entry_i): ditto
(mark_const_tbl): ditto
* internal.h (struct rb_classext_struct): ditto
* object.c (rb_mod_const_set): resolve class name on assignment
* variable.c (const_update): replace with const_tbl_update
(const_tbl_update): new function
(fc_i): adjust for id_table
(find_class_path): ditto
(autoload_const_set): st_update => const_tbl_update
(rb_const_remove): adjust for id_table
(sv_i): ditto
(rb_local_constants_i): ditto
(rb_local_constants): ditto
(rb_mod_const_at): ditto
(rb_mod_const_set): ditto
(rb_const_lookup): ditto
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53376 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-12-29 23:19:14 +03:00
|
|
|
arg.tbl = RCLASS_CONST_TBL(clone) = rb_id_table_create(0);
|
2013-06-14 13:23:54 +04:00
|
|
|
arg.klass = clone;
|
use id_table for constant tables
valgrind 3.9.0 on x86-64 reports a minor reduction in memory usage
when loading only RubyGems and RDoc by running: ruby -rrdoc -eexit
before: HEAP SUMMARY:
in use at exit: 2,913,448 bytes in 27,394 blocks
total heap usage: 48,362 allocs, 20,968 frees, 9,034,621 bytes alloc
after: HEAP SUMMARY:
in use at exit: 2,880,056 bytes in 26,712 blocks
total heap usage: 47,791 allocs, 21,079 frees, 9,046,507 bytes alloc
* class.c (struct clone_const_arg): adjust for id_table
(clone_const): ditto
(clone_const_i): ditto
(rb_mod_init_copy): ditto
(rb_singleton_class_clone_and_attach): ditto
(rb_include_class_new): ditto
(include_modules_at): ditto
* constant.h (rb_free_const_table): ditto
* gc.c (free_const_entry_i): ditto
(rb_free_const_table): ditto
(obj_memsize_of): ditto
(mark_const_entry_i): ditto
(mark_const_tbl): ditto
* internal.h (struct rb_classext_struct): ditto
* object.c (rb_mod_const_set): resolve class name on assignment
* variable.c (const_update): replace with const_tbl_update
(const_tbl_update): new function
(fc_i): adjust for id_table
(find_class_path): ditto
(autoload_const_set): st_update => const_tbl_update
(rb_const_remove): adjust for id_table
(sv_i): ditto
(rb_local_constants_i): ditto
(rb_local_constants): ditto
(rb_mod_const_at): ditto
(rb_mod_const_set): ditto
(rb_const_lookup): ditto
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53376 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-12-29 23:19:14 +03:00
|
|
|
rb_id_table_foreach(RCLASS_CONST_TBL(klass), clone_const_i, &arg);
|
2010-10-26 21:27:21 +04:00
|
|
|
}
|
2012-12-29 06:37:47 +04:00
|
|
|
if (attach != Qundef) {
|
|
|
|
rb_singleton_class_attached(clone, attach);
|
|
|
|
}
|
2013-12-03 12:11:07 +04:00
|
|
|
RCLASS_M_TBL_INIT(clone);
|
2015-06-03 22:36:52 +03:00
|
|
|
{
|
|
|
|
struct clone_method_arg arg;
|
|
|
|
arg.old_klass = klass;
|
|
|
|
arg.new_klass = clone;
|
2015-08-12 11:43:55 +03:00
|
|
|
rb_id_table_foreach(RCLASS_M_TBL(klass), clone_method_i, &arg);
|
2015-06-03 22:36:52 +03:00
|
|
|
}
|
2020-11-12 00:38:03 +03:00
|
|
|
if (klass_of_clone_is_new) {
|
2022-02-19 15:33:53 +03:00
|
|
|
rb_singleton_class_attached(METACLASS_OF(clone), clone);
|
2020-11-12 00:38:03 +03:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
FL_SET(clone, FL_SINGLETON);
|
2013-06-14 13:23:54 +04:00
|
|
|
|
2011-05-31 20:16:06 +04:00
|
|
|
return clone;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
void
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_singleton_class_attached(VALUE klass, VALUE obj)
|
1998-01-16 15:19:22 +03:00
|
|
|
{
|
2001-05-02 08:22:21 +04:00
|
|
|
if (FL_TEST(klass, FL_SINGLETON)) {
|
2015-10-30 06:07:06 +03:00
|
|
|
rb_class_ivar_set(klass, id_attached, obj);
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
|
2009-06-29 20:39:28 +04:00
|
|
|
/*!
|
2009-08-31 09:55:57 +04:00
|
|
|
* whether k is a meta^(n)-class of Class class
|
|
|
|
* @retval 1 if \a k is a meta^(n)-class of Class class (n >= 0)
|
|
|
|
* @retval 0 otherwise
|
2009-06-29 20:39:28 +04:00
|
|
|
*/
|
2010-12-04 05:18:42 +03:00
|
|
|
#define META_CLASS_OF_CLASS_CLASS_P(k) (METACLASS_OF(k) == (k))
|
2009-08-31 09:55:57 +04:00
|
|
|
|
2015-12-22 16:15:58 +03:00
|
|
|
static int
|
|
|
|
rb_singleton_class_has_metaclass_p(VALUE sklass)
|
|
|
|
{
|
|
|
|
return rb_attr_get(METACLASS_OF(sklass), id_attached) == sklass;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rb_singleton_class_internal_p(VALUE sklass)
|
|
|
|
{
|
|
|
|
return (RB_TYPE_P(rb_attr_get(sklass, id_attached), T_CLASS) &&
|
|
|
|
!rb_singleton_class_has_metaclass_p(sklass));
|
|
|
|
}
|
|
|
|
|
2013-03-31 01:27:27 +04:00
|
|
|
/*!
|
|
|
|
* whether k has a metaclass
|
|
|
|
* @retval 1 if \a k has a metaclass
|
|
|
|
* @retval 0 otherwise
|
|
|
|
*/
|
|
|
|
#define HAVE_METACLASS_P(k) \
|
|
|
|
(FL_TEST(METACLASS_OF(k), FL_SINGLETON) && \
|
2015-12-22 16:15:58 +03:00
|
|
|
rb_singleton_class_has_metaclass_p(k))
|
2009-08-31 09:55:57 +04:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* ensures \a klass belongs to its own eigenclass.
|
|
|
|
* @return the eigenclass of \a klass
|
|
|
|
* @post \a klass belongs to the returned eigenclass.
|
|
|
|
* i.e. the attached object of the eigenclass is \a klass.
|
|
|
|
* @note this macro creates a new eigenclass if necessary.
|
|
|
|
*/
|
|
|
|
#define ENSURE_EIGENCLASS(klass) \
|
2013-03-31 01:27:27 +04:00
|
|
|
(HAVE_METACLASS_P(klass) ? METACLASS_OF(klass) : make_metaclass(klass))
|
2009-08-31 09:55:57 +04:00
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Creates a metaclass of \a klass
|
|
|
|
* \param klass a class
|
|
|
|
* \return created metaclass for the class
|
|
|
|
* \pre \a klass is a Class object
|
|
|
|
* \pre \a klass has no singleton class.
|
|
|
|
* \post the class of \a klass is the returned class.
|
|
|
|
* \post the returned class is meta^(n+1)-class when \a klass is a meta^(n)-klass for n >= 0
|
|
|
|
*/
|
|
|
|
static inline VALUE
|
|
|
|
make_metaclass(VALUE klass)
|
* test/ruby/test_metaclass.rb: new test case for metaclass hierarchy.
* class.c (make_metametaclass): new function. extracted from
rb_make_metaclass.
* class.c (rb_make_metaclass): uses make_metametaclass when called for a
metaclass.
* class.c (rb_singleton_class): creates a meta^(n+2)-class in
addition to a meta^(n+1)-class when called for a meta^(n)-class.
This is because the returned meta^(n+1) class must acts as an instance of
Class, metaclass of Class, ..., meta^(n+1)-class of Class,
Module, metaclass of Module, ..., meta^(n+1)-class of Module,
Object, metaclass of Object, ..., meta^(n+2)-class of Object,
BasicObject, metaclass of BasicObject, ..., meta^(n+2)-class of
and BasicObject even when Class, Module, Object or BasicObject has
not have its meta^(i)-class yet.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@20747 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-12-15 09:23:43 +03:00
|
|
|
{
|
2009-08-31 09:55:57 +04:00
|
|
|
VALUE super;
|
|
|
|
VALUE metaclass = rb_class_boot(Qundef);
|
* test/ruby/test_metaclass.rb: new test case for metaclass hierarchy.
* class.c (make_metametaclass): new function. extracted from
rb_make_metaclass.
* class.c (rb_make_metaclass): uses make_metametaclass when called for a
metaclass.
* class.c (rb_singleton_class): creates a meta^(n+2)-class in
addition to a meta^(n+1)-class when called for a meta^(n)-class.
This is because the returned meta^(n+1) class must acts as an instance of
Class, metaclass of Class, ..., meta^(n+1)-class of Class,
Module, metaclass of Module, ..., meta^(n+1)-class of Module,
Object, metaclass of Object, ..., meta^(n+2)-class of Object,
BasicObject, metaclass of BasicObject, ..., meta^(n+2)-class of
and BasicObject even when Class, Module, Object or BasicObject has
not have its meta^(i)-class yet.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@20747 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-12-15 09:23:43 +03:00
|
|
|
|
2009-08-31 09:55:57 +04:00
|
|
|
FL_SET(metaclass, FL_SINGLETON);
|
|
|
|
rb_singleton_class_attached(metaclass, klass);
|
|
|
|
|
|
|
|
if (META_CLASS_OF_CLASS_CLASS_P(klass)) {
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
SET_METACLASS_OF(klass, metaclass);
|
|
|
|
SET_METACLASS_OF(metaclass, metaclass);
|
* test/ruby/test_metaclass.rb: new test case for metaclass hierarchy.
* class.c (make_metametaclass): new function. extracted from
rb_make_metaclass.
* class.c (rb_make_metaclass): uses make_metametaclass when called for a
metaclass.
* class.c (rb_singleton_class): creates a meta^(n+2)-class in
addition to a meta^(n+1)-class when called for a meta^(n)-class.
This is because the returned meta^(n+1) class must acts as an instance of
Class, metaclass of Class, ..., meta^(n+1)-class of Class,
Module, metaclass of Module, ..., meta^(n+1)-class of Module,
Object, metaclass of Object, ..., meta^(n+2)-class of Object,
BasicObject, metaclass of BasicObject, ..., meta^(n+2)-class of
and BasicObject even when Class, Module, Object or BasicObject has
not have its meta^(i)-class yet.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@20747 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-12-15 09:23:43 +03:00
|
|
|
}
|
|
|
|
else {
|
2009-08-31 09:55:57 +04:00
|
|
|
VALUE tmp = METACLASS_OF(klass); /* for a meta^(n)-class klass, tmp is meta^(n)-class of Class class */
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
SET_METACLASS_OF(klass, metaclass);
|
|
|
|
SET_METACLASS_OF(metaclass, ENSURE_EIGENCLASS(tmp));
|
* test/ruby/test_metaclass.rb: new test case for metaclass hierarchy.
* class.c (make_metametaclass): new function. extracted from
rb_make_metaclass.
* class.c (rb_make_metaclass): uses make_metametaclass when called for a
metaclass.
* class.c (rb_singleton_class): creates a meta^(n+2)-class in
addition to a meta^(n+1)-class when called for a meta^(n)-class.
This is because the returned meta^(n+1) class must acts as an instance of
Class, metaclass of Class, ..., meta^(n+1)-class of Class,
Module, metaclass of Module, ..., meta^(n+1)-class of Module,
Object, metaclass of Object, ..., meta^(n+2)-class of Object,
BasicObject, metaclass of BasicObject, ..., meta^(n+2)-class of
and BasicObject even when Class, Module, Object or BasicObject has
not have its meta^(i)-class yet.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@20747 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-12-15 09:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-08-31 09:55:57 +04:00
|
|
|
super = RCLASS_SUPER(klass);
|
2010-12-05 11:56:42 +03:00
|
|
|
while (RB_TYPE_P(super, T_ICLASS)) super = RCLASS_SUPER(super);
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RCLASS_SET_SUPER(metaclass, super ? ENSURE_EIGENCLASS(super) : rb_cClass);
|
2009-08-31 09:55:57 +04:00
|
|
|
|
2022-01-26 06:16:57 +03:00
|
|
|
// Full class ancestry may not have been filled until we reach here.
|
|
|
|
rb_class_update_superclasses(METACLASS_OF(metaclass));
|
|
|
|
|
2009-08-31 09:55:57 +04:00
|
|
|
return metaclass;
|
|
|
|
}
|
* test/ruby/test_metaclass.rb: new test case for metaclass hierarchy.
* class.c (make_metametaclass): new function. extracted from
rb_make_metaclass.
* class.c (rb_make_metaclass): uses make_metametaclass when called for a
metaclass.
* class.c (rb_singleton_class): creates a meta^(n+2)-class in
addition to a meta^(n+1)-class when called for a meta^(n)-class.
This is because the returned meta^(n+1) class must acts as an instance of
Class, metaclass of Class, ..., meta^(n+1)-class of Class,
Module, metaclass of Module, ..., meta^(n+1)-class of Module,
Object, metaclass of Object, ..., meta^(n+2)-class of Object,
BasicObject, metaclass of BasicObject, ..., meta^(n+2)-class of
and BasicObject even when Class, Module, Object or BasicObject has
not have its meta^(i)-class yet.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@20747 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-12-15 09:23:43 +03:00
|
|
|
|
2009-08-31 09:55:57 +04:00
|
|
|
/*!
|
|
|
|
* Creates a singleton class for \a obj.
|
|
|
|
* \pre \a obj must not a immediate nor a special const.
|
|
|
|
* \pre \a obj must not a Class object.
|
|
|
|
* \pre \a obj has no singleton class.
|
|
|
|
*/
|
|
|
|
static inline VALUE
|
|
|
|
make_singleton_class(VALUE obj)
|
|
|
|
{
|
2022-02-19 15:33:53 +03:00
|
|
|
VALUE orig_class = METACLASS_OF(obj);
|
2009-08-31 11:21:54 +04:00
|
|
|
VALUE klass = rb_class_boot(orig_class);
|
2009-08-31 09:55:57 +04:00
|
|
|
|
|
|
|
FL_SET(klass, FL_SINGLETON);
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RBASIC_SET_CLASS(obj, klass);
|
2009-08-31 09:55:57 +04:00
|
|
|
rb_singleton_class_attached(klass, obj);
|
|
|
|
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
SET_METACLASS_OF(klass, METACLASS_OF(rb_class_real(orig_class)));
|
2009-08-31 09:55:57 +04:00
|
|
|
return klass;
|
|
|
|
}
|
* test/ruby/test_metaclass.rb: new test case for metaclass hierarchy.
* class.c (make_metametaclass): new function. extracted from
rb_make_metaclass.
* class.c (rb_make_metaclass): uses make_metametaclass when called for a
metaclass.
* class.c (rb_singleton_class): creates a meta^(n+2)-class in
addition to a meta^(n+1)-class when called for a meta^(n)-class.
This is because the returned meta^(n+1) class must acts as an instance of
Class, metaclass of Class, ..., meta^(n+1)-class of Class,
Module, metaclass of Module, ..., meta^(n+1)-class of Module,
Object, metaclass of Object, ..., meta^(n+2)-class of Object,
BasicObject, metaclass of BasicObject, ..., meta^(n+2)-class of
and BasicObject even when Class, Module, Object or BasicObject has
not have its meta^(i)-class yet.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@20747 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-12-15 09:23:43 +03:00
|
|
|
|
2009-08-31 09:55:57 +04:00
|
|
|
|
|
|
|
static VALUE
|
|
|
|
boot_defclass(const char *name, VALUE super)
|
|
|
|
{
|
|
|
|
VALUE obj = rb_class_boot(super);
|
|
|
|
ID id = rb_intern(name);
|
|
|
|
|
|
|
|
rb_const_set((rb_cObject ? rb_cObject : obj), id, obj);
|
2020-11-09 18:27:31 +03:00
|
|
|
rb_vm_add_root_module(obj);
|
2009-08-31 09:55:57 +04:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2021-12-15 01:08:36 +03:00
|
|
|
/***********************************************************************
|
|
|
|
*
|
|
|
|
* Document-class: Refinement
|
|
|
|
*
|
|
|
|
* Refinement is a class of the +self+ (current context) inside +refine+
|
|
|
|
* statement. It allows to import methods from other modules, see #import_methods.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if 0 /* for RDoc */
|
|
|
|
/*
|
|
|
|
* Document-method: Refinement#import_methods
|
|
|
|
*
|
|
|
|
* call-seq:
|
|
|
|
* import_methods(module, ...) -> self
|
|
|
|
*
|
|
|
|
* Imports methods from modules. Unlike Module#include,
|
|
|
|
* Refinement#import_methods copies methods and adds them into the refinement,
|
|
|
|
* so the refinement is activated in the imported methods.
|
|
|
|
*
|
|
|
|
* Note that due to method copying, only methods defined in Ruby code can be imported.
|
|
|
|
*
|
|
|
|
* module StrUtils
|
|
|
|
* def indent(level)
|
|
|
|
* ' ' * level + self
|
|
|
|
* end
|
|
|
|
* end
|
|
|
|
*
|
|
|
|
* module M
|
|
|
|
* refine String do
|
|
|
|
* import_methods StrUtils
|
|
|
|
* end
|
|
|
|
* end
|
|
|
|
*
|
|
|
|
* using M
|
|
|
|
* "foo".indent(3)
|
|
|
|
* #=> " foo"
|
|
|
|
*
|
|
|
|
* module M
|
|
|
|
* refine String do
|
|
|
|
* import_methods Enumerable
|
|
|
|
* # Can't import method which is not defined with Ruby code: Enumerable#drop
|
|
|
|
* end
|
|
|
|
* end
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
refinement_import_methods(int argc, VALUE *argv, VALUE refinement)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
# endif
|
|
|
|
|
2009-08-31 09:55:57 +04:00
|
|
|
void
|
|
|
|
Init_class_hierarchy(void)
|
|
|
|
{
|
|
|
|
rb_cBasicObject = boot_defclass("BasicObject", 0);
|
|
|
|
rb_cObject = boot_defclass("Object", rb_cBasicObject);
|
2016-06-16 10:35:37 +03:00
|
|
|
rb_gc_register_mark_object(rb_cObject);
|
resolve class name earlier and more consistently
This further avoids class name resolution issues which came
about due to relying on hash table ordering before r53376.
Pre-caching the class name when it is never used raises memory
use, but the overall gain from moving away from st still gives
us a small gain. Reverting r53376 and this patch and testing with
"valgrind -v ./ruby -rrdoc -eexit" on x86 (32-bit) shows:
before:
in use at exit: 1,662,239 bytes in 25,286 blocks
total heap usage: 49,514 allocs, 24,228 frees, 6,005,561 bytes allocated
after, with this change:
in use at exit: 1,646,529 bytes in 24,572 blocks
total heap usage: 48,891 allocs, 24,319 frees, 6,003,921 bytes allocated
* class.c (Init_class_hierarchy): resolve name for rb_cObject ASAP
* object.c (rb_mod_const_set): move name resolution to rb_const_set
* variable.c (rb_const_set): do class resolution here
[ruby-core:72807] [Bug #11977]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53518 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-01-12 22:26:07 +03:00
|
|
|
|
|
|
|
/* resolve class name ASAP for order-independence */
|
2019-04-12 06:46:28 +03:00
|
|
|
rb_set_class_path_string(rb_cObject, rb_cObject, rb_fstring_lit("Object"));
|
resolve class name earlier and more consistently
This further avoids class name resolution issues which came
about due to relying on hash table ordering before r53376.
Pre-caching the class name when it is never used raises memory
use, but the overall gain from moving away from st still gives
us a small gain. Reverting r53376 and this patch and testing with
"valgrind -v ./ruby -rrdoc -eexit" on x86 (32-bit) shows:
before:
in use at exit: 1,662,239 bytes in 25,286 blocks
total heap usage: 49,514 allocs, 24,228 frees, 6,005,561 bytes allocated
after, with this change:
in use at exit: 1,646,529 bytes in 24,572 blocks
total heap usage: 48,891 allocs, 24,319 frees, 6,003,921 bytes allocated
* class.c (Init_class_hierarchy): resolve name for rb_cObject ASAP
* object.c (rb_mod_const_set): move name resolution to rb_const_set
* variable.c (rb_const_set): do class resolution here
[ruby-core:72807] [Bug #11977]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53518 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-01-12 22:26:07 +03:00
|
|
|
|
2009-08-31 09:55:57 +04:00
|
|
|
rb_cModule = boot_defclass("Module", rb_cObject);
|
|
|
|
rb_cClass = boot_defclass("Class", rb_cModule);
|
2021-10-21 10:21:08 +03:00
|
|
|
rb_cRefinement = boot_defclass("Refinement", rb_cModule);
|
2009-08-31 09:55:57 +04:00
|
|
|
|
2021-12-15 01:08:36 +03:00
|
|
|
#if 0 /* for RDoc */
|
|
|
|
// we pretend it to be public, otherwise RDoc will ignore it
|
|
|
|
rb_define_method(rb_cRefinement, "import_methods", refinement_import_methods, -1);
|
|
|
|
#endif
|
|
|
|
|
2014-07-03 07:38:10 +04:00
|
|
|
rb_const_set(rb_cObject, rb_intern_const("BasicObject"), rb_cBasicObject);
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RBASIC_SET_CLASS(rb_cClass, rb_cClass);
|
|
|
|
RBASIC_SET_CLASS(rb_cModule, rb_cClass);
|
|
|
|
RBASIC_SET_CLASS(rb_cObject, rb_cClass);
|
2021-10-21 10:21:08 +03:00
|
|
|
RBASIC_SET_CLASS(rb_cRefinement, rb_cClass);
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RBASIC_SET_CLASS(rb_cBasicObject, rb_cClass);
|
2021-10-26 13:34:27 +03:00
|
|
|
|
|
|
|
ENSURE_EIGENCLASS(rb_cRefinement);
|
* test/ruby/test_metaclass.rb: new test case for metaclass hierarchy.
* class.c (make_metametaclass): new function. extracted from
rb_make_metaclass.
* class.c (rb_make_metaclass): uses make_metametaclass when called for a
metaclass.
* class.c (rb_singleton_class): creates a meta^(n+2)-class in
addition to a meta^(n+1)-class when called for a meta^(n)-class.
This is because the returned meta^(n+1) class must acts as an instance of
Class, metaclass of Class, ..., meta^(n+1)-class of Class,
Module, metaclass of Module, ..., meta^(n+1)-class of Module,
Object, metaclass of Object, ..., meta^(n+2)-class of Object,
BasicObject, metaclass of BasicObject, ..., meta^(n+2)-class of
and BasicObject even when Class, Module, Object or BasicObject has
not have its meta^(i)-class yet.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@20747 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-12-15 09:23:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-06-29 20:39:28 +04:00
|
|
|
/*!
|
|
|
|
* \internal
|
2009-08-31 09:55:57 +04:00
|
|
|
* Creates a new *singleton class* for an object.
|
2009-06-29 20:39:28 +04:00
|
|
|
*
|
2009-08-31 09:55:57 +04:00
|
|
|
* \pre \a obj has no singleton class.
|
|
|
|
* \note DO NOT USE the function in an extension libraries. Use \ref rb_singleton_class.
|
|
|
|
* \param obj An object.
|
|
|
|
* \param unused ignored.
|
|
|
|
* \return The singleton class of the object.
|
2009-06-29 20:39:28 +04:00
|
|
|
*/
|
2002-01-10 23:18:39 +03:00
|
|
|
VALUE
|
2009-08-31 09:55:57 +04:00
|
|
|
rb_make_metaclass(VALUE obj, VALUE unused)
|
2002-01-10 23:18:39 +03:00
|
|
|
{
|
2009-08-31 09:55:57 +04:00
|
|
|
if (BUILTIN_TYPE(obj) == T_CLASS) {
|
|
|
|
return make_metaclass(obj);
|
2002-09-25 11:03:05 +04:00
|
|
|
}
|
|
|
|
else {
|
2009-08-31 09:55:57 +04:00
|
|
|
return make_singleton_class(obj);
|
2002-09-03 09:20:14 +04:00
|
|
|
}
|
2002-01-10 23:18:39 +03:00
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_define_class_id(ID id, VALUE super)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
if (!super) super = rb_cObject;
|
|
|
|
klass = rb_class_new(super);
|
2022-02-19 15:33:53 +03:00
|
|
|
rb_make_metaclass(klass, METACLASS_OF(super));
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
return klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2009-08-29 17:39:44 +04:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* Calls Class#inherited.
|
|
|
|
* \param super A class which will be called #inherited.
|
|
|
|
* NULL means Object class.
|
|
|
|
* \param klass A Class object which derived from \a super
|
|
|
|
* \return the value \c Class#inherited's returns
|
|
|
|
* \pre Each of \a super and \a klass must be a \c Class object.
|
|
|
|
*/
|
mjit_compile.c: merge initial JIT compiler
which has been developed by Takashi Kokubun <takashikkbn@gmail> as
YARV-MJIT. Many of its bugs are fixed by wanabe <s.wanabe@gmail.com>.
This JIT compiler is designed to be a safe migration path to introduce
JIT compiler to MRI. So this commit does not include any bytecode
changes or dynamic instruction modifications, which are done in original
MJIT.
This commit even strips off some aggressive optimizations from
YARV-MJIT, and thus it's slower than YARV-MJIT too. But it's still
fairly faster than Ruby 2.5 in some benchmarks (attached below).
Note that this JIT compiler passes `make test`, `make test-all`, `make
test-spec` without JIT, and even with JIT. Not only it's perfectly safe
with JIT disabled because it does not replace VM instructions unlike
MJIT, but also with JIT enabled it stably runs Ruby applications
including Rails applications.
I'm expecting this version as just "initial" JIT compiler. I have many
optimization ideas which are skipped for initial merging, and you may
easily replace this JIT compiler with a faster one by just replacing
mjit_compile.c. `mjit_compile` interface is designed for the purpose.
common.mk: update dependencies for mjit_compile.c.
internal.h: declare `rb_vm_insn_addr2insn` for MJIT.
vm.c: exclude some definitions if `-DMJIT_HEADER` is provided to
compiler. This avoids to include some functions which take a long time
to compile, e.g. vm_exec_core. Some of the purpose is achieved in
transform_mjit_header.rb (see `IGNORED_FUNCTIONS`) but others are
manually resolved for now. Load mjit_helper.h for MJIT header.
mjit_helper.h: New. This is a file used only by JIT-ed code. I'll
refactor `mjit_call_cfunc` later.
vm_eval.c: add some #ifdef switches to skip compiling some functions
like Init_vm_eval.
win32/mkexports.rb: export thread/ec functions, which are used by MJIT.
include/ruby/defines.h: add MJIT_FUNC_EXPORTED macro alis to clarify
that a function is exported only for MJIT.
array.c: export a function used by MJIT.
bignum.c: ditto.
class.c: ditto.
compile.c: ditto.
error.c: ditto.
gc.c: ditto.
hash.c: ditto.
iseq.c: ditto.
numeric.c: ditto.
object.c: ditto.
proc.c: ditto.
re.c: ditto.
st.c: ditto.
string.c: ditto.
thread.c: ditto.
variable.c: ditto.
vm_backtrace.c: ditto.
vm_insnhelper.c: ditto.
vm_method.c: ditto.
I would like to improve maintainability of function exports, but I
believe this way is acceptable as initial merging if we clarify the
new exports are for MJIT (so that we can use them as TODO list to fix)
and add unit tests to detect unresolved symbols.
I'll add unit tests of JIT compilations in succeeding commits.
Author: Takashi Kokubun <takashikkbn@gmail.com>
Contributor: wanabe <s.wanabe@gmail.com>
Part of [Feature #14235]
---
* Known issues
* Code generated by gcc is faster than clang. The benchmark may be worse
in macOS. Following benchmark result is provided by gcc w/ Linux.
* Performance is decreased when Google Chrome is running
* JIT can work on MinGW, but it doesn't improve performance at least
in short running benchmark.
* Currently it doesn't perform well with Rails. We'll try to fix this
before release.
---
* Benchmark reslts
Benchmarked with:
Intel 4.0GHz i7-4790K with 16GB memory under x86-64 Ubuntu 8 Cores
- 2.0.0-p0: Ruby 2.0.0-p0
- r62186: Ruby trunk (early 2.6.0), before MJIT changes
- JIT off: On this commit, but without `--jit` option
- JIT on: On this commit, and with `--jit` option
** Optcarrot fps
Benchmark: https://github.com/mame/optcarrot
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:--------|:--------|:--------|:--------|:--------|
|fps |37.32 |51.46 |51.31 |58.88 |
|vs 2.0.0 |1.00x |1.38x |1.37x |1.58x |
** MJIT benchmarks
Benchmark: https://github.com/benchmark-driver/mjit-benchmarks
(Original: https://github.com/vnmakarov/ruby/tree/rtl_mjit_branch/MJIT-benchmarks)
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:----------|:--------|:--------|:--------|:--------|
|aread |1.00 |1.09 |1.07 |2.19 |
|aref |1.00 |1.13 |1.11 |2.22 |
|aset |1.00 |1.50 |1.45 |2.64 |
|awrite |1.00 |1.17 |1.13 |2.20 |
|call |1.00 |1.29 |1.26 |2.02 |
|const2 |1.00 |1.10 |1.10 |2.19 |
|const |1.00 |1.11 |1.10 |2.19 |
|fannk |1.00 |1.04 |1.02 |1.00 |
|fib |1.00 |1.32 |1.31 |1.84 |
|ivread |1.00 |1.13 |1.12 |2.43 |
|ivwrite |1.00 |1.23 |1.21 |2.40 |
|mandelbrot |1.00 |1.13 |1.16 |1.28 |
|meteor |1.00 |2.97 |2.92 |3.17 |
|nbody |1.00 |1.17 |1.15 |1.49 |
|nest-ntimes|1.00 |1.22 |1.20 |1.39 |
|nest-while |1.00 |1.10 |1.10 |1.37 |
|norm |1.00 |1.18 |1.16 |1.24 |
|nsvb |1.00 |1.16 |1.16 |1.17 |
|red-black |1.00 |1.02 |0.99 |1.12 |
|sieve |1.00 |1.30 |1.28 |1.62 |
|trees |1.00 |1.14 |1.13 |1.19 |
|while |1.00 |1.12 |1.11 |2.41 |
** Discourse's script/bench.rb
Benchmark: https://github.com/discourse/discourse/blob/v1.8.7/script/bench.rb
NOTE: Rails performance was somehow a little degraded with JIT for now.
We should fix this.
(At least I know opt_aref is performing badly in JIT and I have an idea
to fix it. Please wait for the fix.)
*** JIT off
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 17
75: 18
90: 22
99: 29
home_admin:
50: 21
75: 21
90: 27
99: 40
topic_admin:
50: 17
75: 18
90: 22
99: 32
categories:
50: 35
75: 41
90: 43
99: 77
home:
50: 39
75: 46
90: 49
99: 95
topic:
50: 46
75: 52
90: 56
99: 101
*** JIT on
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 19
75: 21
90: 25
99: 33
home_admin:
50: 24
75: 26
90: 30
99: 35
topic_admin:
50: 19
75: 20
90: 25
99: 30
categories:
50: 40
75: 44
90: 48
99: 76
home:
50: 42
75: 48
90: 51
99: 89
topic:
50: 49
75: 55
90: 58
99: 99
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62197 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 14:22:28 +03:00
|
|
|
MJIT_FUNC_EXPORTED VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_class_inherited(VALUE super, VALUE klass)
|
2002-01-10 23:18:39 +03:00
|
|
|
{
|
2008-06-09 13:25:32 +04:00
|
|
|
ID inherited;
|
2002-01-16 05:20:25 +03:00
|
|
|
if (!super) super = rb_cObject;
|
2008-06-09 13:25:32 +04:00
|
|
|
CONST_ID(inherited, "inherited");
|
|
|
|
return rb_funcall(super, inherited, 1, klass);
|
2002-01-10 23:18:39 +03:00
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_define_class(const char *name, VALUE super)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
ID id;
|
|
|
|
|
|
|
|
id = rb_intern(name);
|
2001-05-02 08:22:21 +04:00
|
|
|
if (rb_const_defined(rb_cObject, id)) {
|
|
|
|
klass = rb_const_get(rb_cObject, id);
|
2011-09-29 15:07:45 +04:00
|
|
|
if (!RB_TYPE_P(klass, T_CLASS)) {
|
2015-09-27 17:32:50 +03:00
|
|
|
rb_raise(rb_eTypeError, "%s is not a class (%"PRIsVALUE")",
|
|
|
|
name, rb_obj_class(klass));
|
2001-12-18 11:47:06 +03:00
|
|
|
}
|
2007-09-28 10:21:46 +04:00
|
|
|
if (rb_class_real(RCLASS_SUPER(klass)) != super) {
|
2010-01-09 22:54:38 +03:00
|
|
|
rb_raise(rb_eTypeError, "superclass mismatch for class %s", name);
|
2001-12-18 11:47:06 +03:00
|
|
|
}
|
2019-04-23 03:14:36 +03:00
|
|
|
|
|
|
|
/* Class may have been defined in Ruby and not pin-rooted */
|
2020-11-09 18:27:31 +03:00
|
|
|
rb_vm_add_root_module(klass);
|
2001-12-18 11:47:06 +03:00
|
|
|
return klass;
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
2002-02-17 17:44:14 +03:00
|
|
|
if (!super) {
|
2016-03-07 07:33:00 +03:00
|
|
|
rb_raise(rb_eArgError, "no super class for `%s'", name);
|
2002-02-17 17:44:14 +03:00
|
|
|
}
|
1998-01-16 15:19:22 +03:00
|
|
|
klass = rb_define_class_id(id, super);
|
2020-11-09 18:27:31 +03:00
|
|
|
rb_vm_add_root_module(klass);
|
2003-07-01 05:36:25 +04:00
|
|
|
rb_const_set(rb_cObject, id, klass);
|
2003-01-07 10:36:40 +03:00
|
|
|
rb_class_inherited(super, klass);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
return klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_define_class_under(VALUE outer, const char *name, VALUE super)
|
2009-08-12 10:32:21 +04:00
|
|
|
{
|
|
|
|
return rb_define_class_id_under(outer, rb_intern(name), super);
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_define_class_id_under(VALUE outer, ID id, VALUE super)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2001-05-02 08:22:21 +04:00
|
|
|
if (rb_const_defined_at(outer, id)) {
|
2003-06-20 11:11:44 +04:00
|
|
|
klass = rb_const_get_at(outer, id);
|
2011-09-29 15:07:45 +04:00
|
|
|
if (!RB_TYPE_P(klass, T_CLASS)) {
|
2015-09-27 17:32:50 +03:00
|
|
|
rb_raise(rb_eTypeError, "%"PRIsVALUE"::%"PRIsVALUE" is not a class"
|
|
|
|
" (%"PRIsVALUE")",
|
|
|
|
outer, rb_id2str(id), rb_obj_class(klass));
|
2001-12-18 11:47:06 +03:00
|
|
|
}
|
2007-09-28 10:21:46 +04:00
|
|
|
if (rb_class_real(RCLASS_SUPER(klass)) != super) {
|
2015-09-27 17:32:50 +03:00
|
|
|
rb_raise(rb_eTypeError, "superclass mismatch for class "
|
|
|
|
"%"PRIsVALUE"::%"PRIsVALUE""
|
|
|
|
" (%"PRIsVALUE" is given but was %"PRIsVALUE")",
|
|
|
|
outer, rb_id2str(id), RCLASS_SUPER(klass), super);
|
2001-12-18 11:47:06 +03:00
|
|
|
}
|
2019-04-20 04:19:47 +03:00
|
|
|
/* Class may have been defined in Ruby and not pin-rooted */
|
2020-11-09 18:27:31 +03:00
|
|
|
rb_vm_add_root_module(klass);
|
2019-04-20 04:19:47 +03:00
|
|
|
|
2001-12-18 11:47:06 +03:00
|
|
|
return klass;
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
2002-02-17 17:44:14 +03:00
|
|
|
if (!super) {
|
2016-03-07 07:33:00 +03:00
|
|
|
rb_raise(rb_eArgError, "no super class for `%"PRIsVALUE"::%"PRIsVALUE"'",
|
|
|
|
rb_class_path(outer), rb_id2str(id));
|
2002-02-17 17:44:14 +03:00
|
|
|
}
|
1998-01-16 15:19:22 +03:00
|
|
|
klass = rb_define_class_id(id, super);
|
2009-08-12 10:32:21 +04:00
|
|
|
rb_set_class_path_string(klass, outer, rb_id2str(id));
|
2002-01-10 23:18:39 +03:00
|
|
|
rb_const_set(outer, id, klass);
|
2003-01-07 10:36:40 +03:00
|
|
|
rb_class_inherited(super, klass);
|
2020-11-09 18:27:31 +03:00
|
|
|
rb_vm_add_root_module(klass);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
return klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2020-07-26 05:52:19 +03:00
|
|
|
VALUE
|
|
|
|
rb_module_s_alloc(VALUE klass)
|
|
|
|
{
|
|
|
|
VALUE mod = class_alloc(T_MODULE, klass);
|
|
|
|
RCLASS_M_TBL_INIT(mod);
|
2021-09-23 19:30:00 +03:00
|
|
|
FL_SET(mod, RMODULE_ALLOCATED_BUT_NOT_INITIALIZED);
|
2020-07-26 05:52:19 +03:00
|
|
|
return mod;
|
|
|
|
}
|
|
|
|
|
2021-10-21 10:21:08 +03:00
|
|
|
static inline VALUE
|
|
|
|
module_new(VALUE klass)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2021-10-21 10:21:08 +03:00
|
|
|
VALUE mdl = class_alloc(T_MODULE, klass);
|
2013-12-03 12:11:07 +04:00
|
|
|
RCLASS_M_TBL_INIT(mdl);
|
1998-01-16 15:13:05 +03:00
|
|
|
return (VALUE)mdl;
|
|
|
|
}
|
|
|
|
|
2021-10-21 10:21:08 +03:00
|
|
|
VALUE
|
|
|
|
rb_module_new(void)
|
|
|
|
{
|
|
|
|
return module_new(rb_cModule);
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_refinement_new(void)
|
|
|
|
{
|
|
|
|
return module_new(rb_cRefinement);
|
|
|
|
}
|
|
|
|
|
2020-11-26 01:05:06 +03:00
|
|
|
// Kept for compatibility. Use rb_module_new() instead.
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_define_module_id(ID id)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2019-10-09 18:34:03 +03:00
|
|
|
return rb_module_new();
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_define_module(const char *name)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
VALUE module;
|
|
|
|
ID id;
|
|
|
|
|
|
|
|
id = rb_intern(name);
|
2001-05-02 08:22:21 +04:00
|
|
|
if (rb_const_defined(rb_cObject, id)) {
|
|
|
|
module = rb_const_get(rb_cObject, id);
|
2015-09-27 17:32:50 +03:00
|
|
|
if (!RB_TYPE_P(module, T_MODULE)) {
|
|
|
|
rb_raise(rb_eTypeError, "%s is not a module (%"PRIsVALUE")",
|
|
|
|
name, rb_obj_class(module));
|
|
|
|
}
|
2019-04-20 04:19:47 +03:00
|
|
|
/* Module may have been defined in Ruby and not pin-rooted */
|
2020-11-09 18:27:31 +03:00
|
|
|
rb_vm_add_root_module(module);
|
2015-09-27 17:32:50 +03:00
|
|
|
return module;
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
2020-11-26 01:05:06 +03:00
|
|
|
module = rb_module_new();
|
2020-11-09 18:27:31 +03:00
|
|
|
rb_vm_add_root_module(module);
|
2003-07-01 05:36:25 +04:00
|
|
|
rb_const_set(rb_cObject, id, module);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
return module;
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_define_module_under(VALUE outer, const char *name)
|
2009-08-12 10:32:21 +04:00
|
|
|
{
|
|
|
|
return rb_define_module_id_under(outer, rb_intern(name));
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
2009-08-12 10:54:45 +04:00
|
|
|
rb_define_module_id_under(VALUE outer, ID id)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
VALUE module;
|
|
|
|
|
2002-01-07 08:27:01 +03:00
|
|
|
if (rb_const_defined_at(outer, id)) {
|
2003-06-20 11:11:44 +04:00
|
|
|
module = rb_const_get_at(outer, id);
|
2015-09-27 17:32:50 +03:00
|
|
|
if (!RB_TYPE_P(module, T_MODULE)) {
|
|
|
|
rb_raise(rb_eTypeError, "%"PRIsVALUE"::%"PRIsVALUE" is not a module"
|
|
|
|
" (%"PRIsVALUE")",
|
|
|
|
outer, rb_id2str(id), rb_obj_class(module));
|
|
|
|
}
|
2020-12-11 05:24:19 +03:00
|
|
|
/* Module may have been defined in Ruby and not pin-rooted */
|
|
|
|
rb_gc_register_mark_object(module);
|
2015-09-27 17:32:50 +03:00
|
|
|
return module;
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
2020-11-26 01:05:06 +03:00
|
|
|
module = rb_module_new();
|
1999-12-14 09:50:43 +03:00
|
|
|
rb_const_set(outer, id, module);
|
2009-08-12 10:54:45 +04:00
|
|
|
rb_set_class_path_string(module, outer, rb_id2str(id));
|
2010-10-17 05:40:22 +04:00
|
|
|
rb_gc_register_mark_object(module);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
return module;
|
|
|
|
}
|
|
|
|
|
2012-08-02 15:34:19 +04:00
|
|
|
VALUE
|
|
|
|
rb_include_class_new(VALUE module, VALUE super)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2007-09-28 10:21:46 +04:00
|
|
|
VALUE klass = class_alloc(T_ICLASS, rb_cClass);
|
2019-10-12 10:01:37 +03:00
|
|
|
|
2020-08-11 01:19:17 +03:00
|
|
|
RCLASS_M_TBL(klass) = RCLASS_M_TBL(module);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2020-04-05 22:10:42 +03:00
|
|
|
RCLASS_SET_ORIGIN(klass, klass);
|
2002-07-11 12:22:18 +04:00
|
|
|
if (BUILTIN_TYPE(module) == T_ICLASS) {
|
2022-02-19 15:33:53 +03:00
|
|
|
module = METACLASS_OF(module);
|
2002-07-11 12:22:18 +04:00
|
|
|
}
|
2020-06-17 00:45:45 +03:00
|
|
|
RUBY_ASSERT(!RB_TYPE_P(module, T_ICLASS));
|
2007-09-28 10:21:46 +04:00
|
|
|
if (!RCLASS_IV_TBL(module)) {
|
|
|
|
RCLASS_IV_TBL(module) = st_init_numtable();
|
1999-08-13 09:45:20 +04:00
|
|
|
}
|
2010-10-26 21:27:21 +04:00
|
|
|
if (!RCLASS_CONST_TBL(module)) {
|
use id_table for constant tables
valgrind 3.9.0 on x86-64 reports a minor reduction in memory usage
when loading only RubyGems and RDoc by running: ruby -rrdoc -eexit
before: HEAP SUMMARY:
in use at exit: 2,913,448 bytes in 27,394 blocks
total heap usage: 48,362 allocs, 20,968 frees, 9,034,621 bytes alloc
after: HEAP SUMMARY:
in use at exit: 2,880,056 bytes in 26,712 blocks
total heap usage: 47,791 allocs, 21,079 frees, 9,046,507 bytes alloc
* class.c (struct clone_const_arg): adjust for id_table
(clone_const): ditto
(clone_const_i): ditto
(rb_mod_init_copy): ditto
(rb_singleton_class_clone_and_attach): ditto
(rb_include_class_new): ditto
(include_modules_at): ditto
* constant.h (rb_free_const_table): ditto
* gc.c (free_const_entry_i): ditto
(rb_free_const_table): ditto
(obj_memsize_of): ditto
(mark_const_entry_i): ditto
(mark_const_tbl): ditto
* internal.h (struct rb_classext_struct): ditto
* object.c (rb_mod_const_set): resolve class name on assignment
* variable.c (const_update): replace with const_tbl_update
(const_tbl_update): new function
(fc_i): adjust for id_table
(find_class_path): ditto
(autoload_const_set): st_update => const_tbl_update
(rb_const_remove): adjust for id_table
(sv_i): ditto
(rb_local_constants_i): ditto
(rb_local_constants): ditto
(rb_mod_const_at): ditto
(rb_mod_const_set): ditto
(rb_const_lookup): ditto
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53376 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-12-29 23:19:14 +03:00
|
|
|
RCLASS_CONST_TBL(module) = rb_id_table_create(0);
|
2010-10-26 21:27:21 +04:00
|
|
|
}
|
2007-09-28 10:21:46 +04:00
|
|
|
RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module);
|
2021-06-01 20:34:06 +03:00
|
|
|
RCLASS_CVC_TBL(klass) = RCLASS_CVC_TBL(module);
|
2010-10-26 21:27:21 +04:00
|
|
|
RCLASS_CONST_TBL(klass) = RCLASS_CONST_TBL(module);
|
2013-06-23 00:48:35 +04:00
|
|
|
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RCLASS_SET_SUPER(klass, super);
|
2020-06-17 00:45:45 +03:00
|
|
|
RBASIC_SET_CLASS(klass, module);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
return (VALUE)klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2015-01-19 16:08:28 +03:00
|
|
|
static int include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super);
|
2012-06-27 16:31:17 +04:00
|
|
|
|
2017-03-25 05:57:30 +03:00
|
|
|
static void
|
|
|
|
ensure_includable(VALUE klass, VALUE module)
|
|
|
|
{
|
2018-07-27 16:57:14 +03:00
|
|
|
rb_class_modify_check(klass);
|
2017-03-25 05:57:30 +03:00
|
|
|
Check_Type(module, T_MODULE);
|
2021-09-23 18:55:11 +03:00
|
|
|
rb_module_set_initialized(module);
|
2017-03-25 06:23:43 +03:00
|
|
|
if (!NIL_P(rb_refinement_module_get_refined_class(module))) {
|
|
|
|
rb_raise(rb_eArgError, "refinement module is not allowed");
|
|
|
|
}
|
2017-03-25 05:57:30 +03:00
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
void
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_include_module(VALUE klass, VALUE module)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2001-03-28 12:43:25 +04:00
|
|
|
int changed = 0;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2017-03-25 05:57:30 +03:00
|
|
|
ensure_includable(klass, module);
|
2012-06-27 16:31:17 +04:00
|
|
|
|
2015-01-19 16:08:28 +03:00
|
|
|
changed = include_modules_at(klass, RCLASS_ORIGIN(klass), module, TRUE);
|
2012-07-02 12:06:37 +04:00
|
|
|
if (changed < 0)
|
|
|
|
rb_raise(rb_eArgError, "cyclic include detected");
|
2020-01-07 03:41:03 +03:00
|
|
|
|
|
|
|
if (RB_TYPE_P(klass, T_MODULE)) {
|
2021-01-26 19:49:57 +03:00
|
|
|
rb_subclass_entry_t *iclass = RCLASS_SUBCLASSES(klass);
|
2021-11-16 00:09:10 +03:00
|
|
|
// skip the placeholder subclass entry at the head of the list
|
2022-03-16 22:18:34 +03:00
|
|
|
if (iclass) {
|
|
|
|
RUBY_ASSERT(!iclass->klass);
|
2021-11-16 00:09:10 +03:00
|
|
|
iclass = iclass->next;
|
|
|
|
}
|
|
|
|
|
2020-01-07 03:41:03 +03:00
|
|
|
int do_include = 1;
|
|
|
|
while (iclass) {
|
|
|
|
VALUE check_class = iclass->klass;
|
2022-03-16 22:46:40 +03:00
|
|
|
/* During lazy sweeping, iclass->klass could be a dead object that
|
|
|
|
* has not yet been swept. */
|
|
|
|
if (!rb_objspace_garbage_object_p(check_class)) {
|
|
|
|
while (check_class) {
|
|
|
|
RUBY_ASSERT(!rb_objspace_garbage_object_p(check_class));
|
|
|
|
|
|
|
|
if (RB_TYPE_P(check_class, T_ICLASS) &&
|
|
|
|
(METACLASS_OF(check_class) == module)) {
|
|
|
|
do_include = 0;
|
|
|
|
}
|
|
|
|
check_class = RCLASS_SUPER(check_class);
|
2020-01-07 03:41:03 +03:00
|
|
|
}
|
|
|
|
|
2022-03-16 22:46:40 +03:00
|
|
|
if (do_include) {
|
|
|
|
include_modules_at(iclass->klass, RCLASS_ORIGIN(iclass->klass), module, TRUE);
|
|
|
|
}
|
2020-01-07 03:41:03 +03:00
|
|
|
}
|
2022-03-16 22:46:40 +03:00
|
|
|
|
2020-01-07 03:41:03 +03:00
|
|
|
iclass = iclass->next;
|
|
|
|
}
|
|
|
|
}
|
2012-06-27 16:31:17 +04:00
|
|
|
}
|
|
|
|
|
2015-08-12 11:43:55 +03:00
|
|
|
static enum rb_id_table_iterator_result
|
|
|
|
add_refined_method_entry_i(ID key, VALUE value, void *data)
|
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 17:08:41 +04:00
|
|
|
{
|
2015-08-12 11:43:55 +03:00
|
|
|
rb_add_refined_method_entry((VALUE)data, key);
|
2015-08-12 11:59:27 +03:00
|
|
|
return ID_TABLE_CONTINUE;
|
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 17:08:41 +04:00
|
|
|
}
|
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
static enum rb_id_table_iterator_result
|
|
|
|
clear_module_cache_i(ID id, VALUE val, void *data)
|
|
|
|
{
|
|
|
|
VALUE klass = (VALUE)data;
|
|
|
|
rb_clear_method_cache(klass, id);
|
|
|
|
return ID_TABLE_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2021-02-13 06:45:08 +03:00
|
|
|
static bool
|
|
|
|
module_in_super_chain(const VALUE klass, VALUE module)
|
|
|
|
{
|
|
|
|
struct rb_id_table *const klass_m_tbl = RCLASS_M_TBL(RCLASS_ORIGIN(klass));
|
|
|
|
if (klass_m_tbl) {
|
|
|
|
while (module) {
|
|
|
|
if (klass_m_tbl == RCLASS_M_TBL(module))
|
|
|
|
return true;
|
|
|
|
module = RCLASS_SUPER(module);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-03-31 18:04:25 +03:00
|
|
|
// For each ID key in the class constant table, we're going to clear the VM's
|
|
|
|
// inline constant caches associated with it.
|
|
|
|
static enum rb_id_table_iterator_result
|
|
|
|
clear_constant_cache_i(ID id, VALUE value, void *data)
|
|
|
|
{
|
|
|
|
rb_clear_constant_cache_for_id(id);
|
|
|
|
return ID_TABLE_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2012-06-27 16:31:17 +04:00
|
|
|
static int
|
2021-02-13 06:45:08 +03:00
|
|
|
do_include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super, bool check_cyclic)
|
2012-06-27 16:31:17 +04:00
|
|
|
{
|
2020-04-05 22:10:42 +03:00
|
|
|
VALUE p, iclass, origin_stack = 0;
|
2022-03-31 18:04:25 +03:00
|
|
|
int method_changed = 0, add_subclass;
|
2020-04-05 22:10:42 +03:00
|
|
|
long origin_len;
|
2021-01-14 22:59:25 +03:00
|
|
|
VALUE klass_origin = RCLASS_ORIGIN(klass);
|
2020-01-08 10:14:01 +03:00
|
|
|
VALUE original_klass = klass;
|
2012-06-27 16:31:17 +04:00
|
|
|
|
2021-02-13 06:45:08 +03:00
|
|
|
if (check_cyclic && module_in_super_chain(klass, module))
|
|
|
|
return -1;
|
2021-02-10 02:39:34 +03:00
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
while (module) {
|
2021-01-14 22:59:25 +03:00
|
|
|
int c_seen = FALSE;
|
2009-07-18 12:05:32 +04:00
|
|
|
int superclass_seen = FALSE;
|
use id_table for constant tables
valgrind 3.9.0 on x86-64 reports a minor reduction in memory usage
when loading only RubyGems and RDoc by running: ruby -rrdoc -eexit
before: HEAP SUMMARY:
in use at exit: 2,913,448 bytes in 27,394 blocks
total heap usage: 48,362 allocs, 20,968 frees, 9,034,621 bytes alloc
after: HEAP SUMMARY:
in use at exit: 2,880,056 bytes in 26,712 blocks
total heap usage: 47,791 allocs, 21,079 frees, 9,046,507 bytes alloc
* class.c (struct clone_const_arg): adjust for id_table
(clone_const): ditto
(clone_const_i): ditto
(rb_mod_init_copy): ditto
(rb_singleton_class_clone_and_attach): ditto
(rb_include_class_new): ditto
(include_modules_at): ditto
* constant.h (rb_free_const_table): ditto
* gc.c (free_const_entry_i): ditto
(rb_free_const_table): ditto
(obj_memsize_of): ditto
(mark_const_entry_i): ditto
(mark_const_tbl): ditto
* internal.h (struct rb_classext_struct): ditto
* object.c (rb_mod_const_set): resolve class name on assignment
* variable.c (const_update): replace with const_tbl_update
(const_tbl_update): new function
(fc_i): adjust for id_table
(find_class_path): ditto
(autoload_const_set): st_update => const_tbl_update
(rb_const_remove): adjust for id_table
(sv_i): ditto
(rb_local_constants_i): ditto
(rb_local_constants): ditto
(rb_mod_const_at): ditto
(rb_mod_const_set): ditto
(rb_const_lookup): ditto
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53376 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-12-29 23:19:14 +03:00
|
|
|
struct rb_id_table *tbl;
|
2006-11-07 11:56:18 +03:00
|
|
|
|
2021-01-14 22:59:25 +03:00
|
|
|
if (klass == c) {
|
|
|
|
c_seen = TRUE;
|
|
|
|
}
|
|
|
|
if (klass_origin != c || search_super) {
|
|
|
|
/* ignore if the module included already in superclasses for include,
|
|
|
|
* ignore if the module included before origin class for prepend
|
|
|
|
*/
|
|
|
|
for (p = RCLASS_SUPER(klass); p; p = RCLASS_SUPER(p)) {
|
|
|
|
int type = BUILTIN_TYPE(p);
|
|
|
|
if (klass_origin == p && !search_super)
|
|
|
|
break;
|
|
|
|
if (c == p)
|
|
|
|
c_seen = TRUE;
|
|
|
|
if (type == T_ICLASS) {
|
|
|
|
if (RCLASS_M_TBL(p) == RCLASS_M_TBL(module)) {
|
|
|
|
if (!superclass_seen && c_seen) {
|
|
|
|
c = p; /* move insertion point */
|
|
|
|
}
|
|
|
|
goto skip;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (type == T_CLASS) {
|
|
|
|
superclass_seen = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-01-08 10:14:01 +03:00
|
|
|
|
|
|
|
VALUE super_class = RCLASS_SUPER(c);
|
|
|
|
|
|
|
|
// invalidate inline method cache
|
2021-06-01 20:34:06 +03:00
|
|
|
RB_DEBUG_COUNTER_INC(cvar_include_invalidate);
|
|
|
|
ruby_vm_global_cvar_state++;
|
2020-07-22 09:37:28 +03:00
|
|
|
tbl = RCLASS_M_TBL(module);
|
2020-01-08 10:14:01 +03:00
|
|
|
if (tbl && rb_id_table_size(tbl)) {
|
|
|
|
if (search_super) { // include
|
|
|
|
if (super_class && !RB_TYPE_P(super_class, T_MODULE)) {
|
|
|
|
rb_id_table_foreach(tbl, clear_module_cache_i, (void *)super_class);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else { // prepend
|
|
|
|
if (!RB_TYPE_P(original_klass, T_MODULE)) {
|
|
|
|
rb_id_table_foreach(tbl, clear_module_cache_i, (void *)original_klass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
method_changed = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// setup T_ICLASS for the include/prepend module
|
|
|
|
iclass = rb_include_class_new(module, super_class);
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
c = RCLASS_SET_SUPER(c, iclass);
|
2019-08-21 23:59:36 +03:00
|
|
|
RCLASS_SET_INCLUDER(iclass, klass);
|
2020-04-05 22:10:42 +03:00
|
|
|
add_subclass = TRUE;
|
|
|
|
if (module != RCLASS_ORIGIN(module)) {
|
|
|
|
if (!origin_stack) origin_stack = rb_ary_tmp_new(2);
|
|
|
|
VALUE origin[2] = {iclass, RCLASS_ORIGIN(module)};
|
|
|
|
rb_ary_cat(origin_stack, origin, 2);
|
|
|
|
}
|
|
|
|
else if (origin_stack && (origin_len = RARRAY_LEN(origin_stack)) > 1 &&
|
|
|
|
RARRAY_AREF(origin_stack, origin_len - 1) == module) {
|
|
|
|
RCLASS_SET_ORIGIN(RARRAY_AREF(origin_stack, (origin_len -= 2)), iclass);
|
|
|
|
RICLASS_SET_ORIGIN_SHARED_MTBL(iclass);
|
|
|
|
rb_ary_resize(origin_stack, origin_len);
|
|
|
|
add_subclass = FALSE;
|
|
|
|
}
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
|
2021-08-20 08:03:08 +03:00
|
|
|
if (add_subclass) {
|
2015-01-19 16:08:28 +03:00
|
|
|
VALUE m = module;
|
2022-02-19 15:33:53 +03:00
|
|
|
if (BUILTIN_TYPE(m) == T_ICLASS) m = METACLASS_OF(m);
|
2021-08-20 08:03:08 +03:00
|
|
|
rb_module_add_to_subclasses_list(m, iclass);
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
}
|
|
|
|
|
2022-05-05 22:10:36 +03:00
|
|
|
if (BUILTIN_TYPE(klass) == T_MODULE && FL_TEST(klass, RMODULE_IS_REFINEMENT)) {
|
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 17:08:41 +04:00
|
|
|
VALUE refined_class =
|
|
|
|
rb_refinement_module_get_refined_class(klass);
|
|
|
|
|
2020-07-22 09:37:28 +03:00
|
|
|
rb_id_table_foreach(RCLASS_M_TBL(module), add_refined_method_entry_i, (void *)refined_class);
|
2022-05-05 22:10:36 +03:00
|
|
|
RUBY_ASSERT(BUILTIN_TYPE(c) == T_MODULE);
|
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 17:08:41 +04:00
|
|
|
}
|
use id_table for constant tables
valgrind 3.9.0 on x86-64 reports a minor reduction in memory usage
when loading only RubyGems and RDoc by running: ruby -rrdoc -eexit
before: HEAP SUMMARY:
in use at exit: 2,913,448 bytes in 27,394 blocks
total heap usage: 48,362 allocs, 20,968 frees, 9,034,621 bytes alloc
after: HEAP SUMMARY:
in use at exit: 2,880,056 bytes in 26,712 blocks
total heap usage: 47,791 allocs, 21,079 frees, 9,046,507 bytes alloc
* class.c (struct clone_const_arg): adjust for id_table
(clone_const): ditto
(clone_const_i): ditto
(rb_mod_init_copy): ditto
(rb_singleton_class_clone_and_attach): ditto
(rb_include_class_new): ditto
(include_modules_at): ditto
* constant.h (rb_free_const_table): ditto
* gc.c (free_const_entry_i): ditto
(rb_free_const_table): ditto
(obj_memsize_of): ditto
(mark_const_entry_i): ditto
(mark_const_tbl): ditto
* internal.h (struct rb_classext_struct): ditto
* object.c (rb_mod_const_set): resolve class name on assignment
* variable.c (const_update): replace with const_tbl_update
(const_tbl_update): new function
(fc_i): adjust for id_table
(find_class_path): ditto
(autoload_const_set): st_update => const_tbl_update
(rb_const_remove): adjust for id_table
(sv_i): ditto
(rb_local_constants_i): ditto
(rb_local_constants): ditto
(rb_mod_const_at): ditto
(rb_mod_const_set): ditto
(rb_const_lookup): ditto
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53376 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-12-29 23:19:14 +03:00
|
|
|
|
2020-07-22 09:37:28 +03:00
|
|
|
tbl = RCLASS_CONST_TBL(module);
|
2022-03-31 18:04:25 +03:00
|
|
|
if (tbl && rb_id_table_size(tbl))
|
|
|
|
rb_id_table_foreach(tbl, clear_constant_cache_i, NULL);
|
2006-11-07 11:56:18 +03:00
|
|
|
skip:
|
2007-09-28 10:21:46 +04:00
|
|
|
module = RCLASS_SUPER(module);
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
2012-06-27 16:31:17 +04:00
|
|
|
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 09:25:06 +04:00
|
|
|
return method_changed;
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
|
2021-02-13 06:45:08 +03:00
|
|
|
static int
|
|
|
|
include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super)
|
|
|
|
{
|
|
|
|
return do_include_modules_at(klass, c, module, search_super, true);
|
|
|
|
}
|
|
|
|
|
2015-08-12 11:43:55 +03:00
|
|
|
static enum rb_id_table_iterator_result
|
|
|
|
move_refined_method(ID key, VALUE value, void *data)
|
2012-12-12 13:35:50 +04:00
|
|
|
{
|
2020-12-21 23:27:47 +03:00
|
|
|
rb_method_entry_t *me = (rb_method_entry_t *)value;
|
2012-12-12 13:35:50 +04:00
|
|
|
|
|
|
|
if (me->def->type == VM_METHOD_TYPE_REFINED) {
|
2020-12-21 23:27:47 +03:00
|
|
|
VALUE klass = (VALUE)data;
|
|
|
|
struct rb_id_table *tbl = RCLASS_M_TBL(klass);
|
2020-12-18 22:30:25 +03:00
|
|
|
|
|
|
|
if (me->def->body.refined.orig_me) {
|
2019-10-03 06:26:41 +03:00
|
|
|
const rb_method_entry_t *orig_me = me->def->body.refined.orig_me, *new_me;
|
|
|
|
RB_OBJ_WRITE(me, &me->def->body.refined.orig_me, NULL);
|
|
|
|
new_me = rb_method_entry_clone(me);
|
2020-08-11 01:19:17 +03:00
|
|
|
rb_method_table_insert(klass, tbl, key, new_me);
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_entry_copy(me, orig_me);
|
|
|
|
return ID_TABLE_CONTINUE;
|
2012-12-12 13:35:50 +04:00
|
|
|
}
|
|
|
|
else {
|
2020-08-11 01:19:17 +03:00
|
|
|
rb_method_table_insert(klass, tbl, key, me);
|
2015-08-12 11:59:27 +03:00
|
|
|
return ID_TABLE_DELETE;
|
2012-12-12 13:35:50 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2015-08-12 11:59:27 +03:00
|
|
|
return ID_TABLE_CONTINUE;
|
2012-12-12 13:35:50 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-21 23:27:47 +03:00
|
|
|
static enum rb_id_table_iterator_result
|
|
|
|
cache_clear_refined_method(ID key, VALUE value, void *data)
|
|
|
|
{
|
|
|
|
rb_method_entry_t *me = (rb_method_entry_t *) value;
|
|
|
|
|
2021-05-11 19:05:06 +03:00
|
|
|
if (me->def->type == VM_METHOD_TYPE_REFINED && me->def->body.refined.orig_me) {
|
2020-12-21 23:27:47 +03:00
|
|
|
VALUE klass = (VALUE)data;
|
|
|
|
rb_clear_method_cache(klass, me->called_id);
|
|
|
|
}
|
2021-05-11 19:05:06 +03:00
|
|
|
// Refined method entries without an orig_me is going to stay in the method
|
|
|
|
// table of klass, like before the move, so no need to clear the cache.
|
2020-12-21 23:27:47 +03:00
|
|
|
|
|
|
|
return ID_TABLE_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2021-02-13 06:45:08 +03:00
|
|
|
static bool
|
2020-07-23 00:27:03 +03:00
|
|
|
ensure_origin(VALUE klass)
|
2012-06-27 11:48:50 +04:00
|
|
|
{
|
Make prepending a refined module after inclusion not break refinements
After the previous commit, this was still broken. The reason it
was broken is that a refined module that hasn't been prepended to
yet keeps the refined methods in the module's method table. When
prepending, the module's method table is moved to the origin
iclass, and then the refined methods are moved from the method
table to a new method table in the module itself.
Unfortunately, that means that if a class has included the module,
prepending breaks the refinements, because when the methods are
moved from the origin iclass method table to the module method
table, they are removed from the method table from the iclass
created when the module was included earlier.
Fix this by always creating an origin class when including a
module that has any refinements, even if the refinements are
not currently used. I wasn't sure the best way to do that.
The approach I choose was to use an object flag. The flag is
set on the module when Module#refine is called, and if the
flag is present when the module is included in another module
or class, an origin iclass is created for the module.
Fixes [Bug #13446]
2019-10-12 11:02:51 +03:00
|
|
|
VALUE origin = RCLASS_ORIGIN(klass);
|
2012-06-27 11:48:50 +04:00
|
|
|
if (origin == klass) {
|
2012-07-02 12:06:37 +04:00
|
|
|
origin = class_alloc(T_ICLASS, klass);
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RCLASS_SET_SUPER(origin, RCLASS_SUPER(klass));
|
|
|
|
RCLASS_SET_SUPER(klass, origin);
|
2015-03-11 12:15:20 +03:00
|
|
|
RCLASS_SET_ORIGIN(klass, origin);
|
2015-03-06 01:20:14 +03:00
|
|
|
RCLASS_M_TBL(origin) = RCLASS_M_TBL(klass);
|
2013-12-03 12:11:07 +04:00
|
|
|
RCLASS_M_TBL_INIT(klass);
|
2020-12-21 23:27:47 +03:00
|
|
|
rb_id_table_foreach(RCLASS_M_TBL(origin), cache_clear_refined_method, (void *)klass);
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_id_table_foreach(RCLASS_M_TBL(origin), move_refined_method, (void *)klass);
|
2021-02-13 06:45:08 +03:00
|
|
|
return true;
|
2012-06-27 11:48:50 +04:00
|
|
|
}
|
2021-02-13 06:45:08 +03:00
|
|
|
return false;
|
Make prepending a refined module after inclusion not break refinements
After the previous commit, this was still broken. The reason it
was broken is that a refined module that hasn't been prepended to
yet keeps the refined methods in the module's method table. When
prepending, the module's method table is moved to the origin
iclass, and then the refined methods are moved from the method
table to a new method table in the module itself.
Unfortunately, that means that if a class has included the module,
prepending breaks the refinements, because when the methods are
moved from the origin iclass method table to the module method
table, they are removed from the method table from the iclass
created when the module was included earlier.
Fix this by always creating an origin class when including a
module that has any refinements, even if the refinements are
not currently used. I wasn't sure the best way to do that.
The approach I choose was to use an object flag. The flag is
set on the module when Module#refine is called, and if the
flag is present when the module is included in another module
or class, an origin iclass is created for the module.
Fixes [Bug #13446]
2019-10-12 11:02:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_prepend_module(VALUE klass, VALUE module)
|
|
|
|
{
|
2021-02-13 06:45:08 +03:00
|
|
|
int changed;
|
|
|
|
bool klass_had_no_origin;
|
Make prepending a refined module after inclusion not break refinements
After the previous commit, this was still broken. The reason it
was broken is that a refined module that hasn't been prepended to
yet keeps the refined methods in the module's method table. When
prepending, the module's method table is moved to the origin
iclass, and then the refined methods are moved from the method
table to a new method table in the module itself.
Unfortunately, that means that if a class has included the module,
prepending breaks the refinements, because when the methods are
moved from the origin iclass method table to the module method
table, they are removed from the method table from the iclass
created when the module was included earlier.
Fix this by always creating an origin class when including a
module that has any refinements, even if the refinements are
not currently used. I wasn't sure the best way to do that.
The approach I choose was to use an object flag. The flag is
set on the module when Module#refine is called, and if the
flag is present when the module is included in another module
or class, an origin iclass is created for the module.
Fixes [Bug #13446]
2019-10-12 11:02:51 +03:00
|
|
|
|
|
|
|
ensure_includable(klass, module);
|
2021-02-13 06:45:08 +03:00
|
|
|
if (module_in_super_chain(klass, module))
|
|
|
|
rb_raise(rb_eArgError, "cyclic prepend detected");
|
|
|
|
|
|
|
|
klass_had_no_origin = ensure_origin(klass);
|
|
|
|
changed = do_include_modules_at(klass, klass, module, FALSE, false);
|
|
|
|
RUBY_ASSERT(changed >= 0); // already checked for cyclic prepend above
|
2013-03-05 16:36:45 +04:00
|
|
|
if (changed) {
|
|
|
|
rb_vm_check_redefinition_by_prepend(klass);
|
|
|
|
}
|
2020-06-03 22:14:49 +03:00
|
|
|
if (RB_TYPE_P(klass, T_MODULE)) {
|
2021-01-26 19:49:57 +03:00
|
|
|
rb_subclass_entry_t *iclass = RCLASS_SUBCLASSES(klass);
|
2021-11-16 00:09:10 +03:00
|
|
|
// skip the placeholder subclass entry at the head of the list if it exists
|
2022-03-16 22:10:11 +03:00
|
|
|
if (iclass) {
|
2021-11-16 00:09:10 +03:00
|
|
|
RUBY_ASSERT(!iclass->klass);
|
|
|
|
iclass = iclass->next;
|
|
|
|
}
|
|
|
|
|
2020-07-23 00:27:03 +03:00
|
|
|
VALUE klass_origin = RCLASS_ORIGIN(klass);
|
|
|
|
struct rb_id_table *klass_m_tbl = RCLASS_M_TBL(klass);
|
|
|
|
struct rb_id_table *klass_origin_m_tbl = RCLASS_M_TBL(klass_origin);
|
2020-06-03 22:14:49 +03:00
|
|
|
while (iclass) {
|
2022-03-16 22:46:40 +03:00
|
|
|
/* During lazy sweeping, iclass->klass could be a dead object that
|
|
|
|
* has not yet been swept. */
|
|
|
|
if (!rb_objspace_garbage_object_p(iclass->klass)) {
|
2022-05-05 23:08:24 +03:00
|
|
|
const VALUE subclass = iclass->klass;
|
|
|
|
if (klass_had_no_origin && klass_origin_m_tbl == RCLASS_M_TBL(subclass)) {
|
2022-03-16 22:46:40 +03:00
|
|
|
// backfill an origin iclass to handle refinements and future prepends
|
2022-05-05 23:08:24 +03:00
|
|
|
rb_id_table_foreach(RCLASS_M_TBL(subclass), clear_module_cache_i, (void *)subclass);
|
|
|
|
RCLASS_M_TBL(subclass) = klass_m_tbl;
|
|
|
|
VALUE origin = rb_include_class_new(klass_origin, RCLASS_SUPER(subclass));
|
|
|
|
RCLASS_SET_SUPER(subclass, origin);
|
|
|
|
RCLASS_SET_INCLUDER(origin, RCLASS_INCLUDER(subclass));
|
|
|
|
RCLASS_SET_ORIGIN(subclass, origin);
|
2022-03-16 22:46:40 +03:00
|
|
|
RICLASS_SET_ORIGIN_SHARED_MTBL(origin);
|
|
|
|
}
|
2022-05-05 23:08:24 +03:00
|
|
|
include_modules_at(subclass, subclass, module, FALSE);
|
2020-07-23 00:27:03 +03:00
|
|
|
}
|
2022-03-16 22:46:40 +03:00
|
|
|
|
2020-06-03 22:14:49 +03:00
|
|
|
iclass = iclass->next;
|
|
|
|
}
|
|
|
|
}
|
2012-06-27 11:48:50 +04:00
|
|
|
}
|
|
|
|
|
2003-12-28 09:33:07 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* mod.included_modules -> array
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-01-16 22:28:37 +03:00
|
|
|
* Returns the list of modules included or prepended in <i>mod</i>
|
|
|
|
* or one of <i>mod</i>'s ancestors.
|
|
|
|
*
|
|
|
|
* module Sub
|
|
|
|
* end
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-28 09:33:07 +03:00
|
|
|
* module Mixin
|
2020-01-16 22:28:37 +03:00
|
|
|
* prepend Sub
|
2003-12-28 09:33:07 +03:00
|
|
|
* end
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-28 09:33:07 +03:00
|
|
|
* module Outer
|
|
|
|
* include Mixin
|
|
|
|
* end
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-01-16 22:28:37 +03:00
|
|
|
* Mixin.included_modules #=> [Sub]
|
|
|
|
* Outer.included_modules #=> [Sub, Mixin]
|
2003-12-28 09:33:07 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_mod_included_modules(VALUE mod)
|
1998-01-16 15:19:22 +03:00
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE ary = rb_ary_new();
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE p;
|
2013-05-08 17:47:11 +04:00
|
|
|
VALUE origin = RCLASS_ORIGIN(mod);
|
1998-01-16 15:19:22 +03:00
|
|
|
|
2007-09-28 10:21:46 +04:00
|
|
|
for (p = RCLASS_SUPER(mod); p; p = RCLASS_SUPER(p)) {
|
2020-04-05 22:10:42 +03:00
|
|
|
if (p != origin && RCLASS_ORIGIN(p) == p && BUILTIN_TYPE(p) == T_ICLASS) {
|
2022-02-19 15:33:53 +03:00
|
|
|
VALUE m = METACLASS_OF(p);
|
2013-05-08 20:05:50 +04:00
|
|
|
if (RB_TYPE_P(m, T_MODULE))
|
|
|
|
rb_ary_push(ary, m);
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2003-12-28 09:33:07 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* mod.include?(module) -> true or false
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-01-16 22:28:37 +03:00
|
|
|
* Returns <code>true</code> if <i>module</i> is included
|
|
|
|
* or prepended in <i>mod</i> or one of <i>mod</i>'s ancestors.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-28 09:33:07 +03:00
|
|
|
* module A
|
|
|
|
* end
|
|
|
|
* class B
|
|
|
|
* include A
|
|
|
|
* end
|
|
|
|
* class C < B
|
|
|
|
* end
|
|
|
|
* B.include?(A) #=> true
|
|
|
|
* C.include?(A) #=> true
|
|
|
|
* A.include?(A) #=> false
|
|
|
|
*/
|
|
|
|
|
2001-07-24 13:07:33 +04:00
|
|
|
VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_mod_include_p(VALUE mod, VALUE mod2)
|
2001-07-24 13:07:33 +04:00
|
|
|
{
|
|
|
|
VALUE p;
|
|
|
|
|
|
|
|
Check_Type(mod2, T_MODULE);
|
2007-09-28 10:21:46 +04:00
|
|
|
for (p = RCLASS_SUPER(mod); p; p = RCLASS_SUPER(p)) {
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
if (BUILTIN_TYPE(p) == T_ICLASS && !FL_TEST(p, RICLASS_IS_ORIGIN)) {
|
2022-02-19 15:33:53 +03:00
|
|
|
if (METACLASS_OF(p) == mod2) return Qtrue;
|
2001-07-24 13:07:33 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return Qfalse;
|
|
|
|
}
|
|
|
|
|
2003-12-28 09:33:07 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* mod.ancestors -> array
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2014-07-05 09:13:28 +04:00
|
|
|
* Returns a list of modules included/prepended in <i>mod</i>
|
|
|
|
* (including <i>mod</i> itself).
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-28 09:33:07 +03:00
|
|
|
* module Mod
|
|
|
|
* include Math
|
|
|
|
* include Comparable
|
2014-07-05 09:13:28 +04:00
|
|
|
* prepend Enumerable
|
2003-12-28 09:33:07 +03:00
|
|
|
* end
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2014-07-05 09:13:28 +04:00
|
|
|
* Mod.ancestors #=> [Enumerable, Mod, Comparable, Math]
|
|
|
|
* Math.ancestors #=> [Math]
|
|
|
|
* Enumerable.ancestors #=> [Enumerable]
|
2003-12-28 09:33:07 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_mod_ancestors(VALUE mod)
|
1998-01-16 15:19:22 +03:00
|
|
|
{
|
2003-08-07 01:50:06 +04:00
|
|
|
VALUE p, ary = rb_ary_new();
|
2021-08-20 04:42:01 +03:00
|
|
|
VALUE refined_class = Qnil;
|
2022-05-05 22:10:36 +03:00
|
|
|
if (BUILTIN_TYPE(mod) == T_MODULE && FL_TEST(mod, RMODULE_IS_REFINEMENT)) {
|
2021-08-20 04:42:01 +03:00
|
|
|
refined_class = rb_refinement_module_get_refined_class(mod);
|
|
|
|
}
|
1998-01-16 15:19:22 +03:00
|
|
|
|
2012-07-02 12:06:37 +04:00
|
|
|
for (p = mod; p; p = RCLASS_SUPER(p)) {
|
2021-08-20 04:42:01 +03:00
|
|
|
if (p == refined_class) break;
|
2019-10-12 10:01:37 +03:00
|
|
|
if (p != RCLASS_ORIGIN(p)) continue;
|
2012-07-02 12:06:37 +04:00
|
|
|
if (BUILTIN_TYPE(p) == T_ICLASS) {
|
2022-02-19 15:33:53 +03:00
|
|
|
rb_ary_push(ary, METACLASS_OF(p));
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
2019-10-12 10:01:37 +03:00
|
|
|
else {
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_ary_push(ary, p);
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2021-11-02 13:23:36 +03:00
|
|
|
struct subclass_traverse_data
|
|
|
|
{
|
2021-11-09 11:06:01 +03:00
|
|
|
VALUE buffer;
|
2021-11-02 13:23:36 +03:00
|
|
|
long count;
|
2021-11-05 03:36:44 +03:00
|
|
|
long maxcount;
|
2021-10-28 15:07:11 +03:00
|
|
|
bool immediate_only;
|
2021-11-02 13:23:36 +03:00
|
|
|
};
|
|
|
|
|
2021-10-26 22:35:21 +03:00
|
|
|
static void
|
2021-11-02 13:23:36 +03:00
|
|
|
class_descendants_recursive(VALUE klass, VALUE v)
|
2021-10-26 22:35:21 +03:00
|
|
|
{
|
2021-11-02 13:23:36 +03:00
|
|
|
struct subclass_traverse_data *data = (struct subclass_traverse_data *) v;
|
|
|
|
|
2021-10-26 22:35:21 +03:00
|
|
|
if (BUILTIN_TYPE(klass) == T_CLASS && !FL_TEST(klass, FL_SINGLETON)) {
|
2021-11-09 11:06:01 +03:00
|
|
|
if (data->buffer && data->count < data->maxcount && !rb_objspace_garbage_object_p(klass)) {
|
|
|
|
// assumes that this does not cause GC as long as the length does not exceed the capacity
|
|
|
|
rb_ary_push(data->buffer, klass);
|
2021-11-02 13:23:36 +03:00
|
|
|
}
|
|
|
|
data->count++;
|
2021-10-28 15:07:11 +03:00
|
|
|
if (!data->immediate_only) {
|
|
|
|
rb_class_foreach_subclass(klass, class_descendants_recursive, v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_class_foreach_subclass(klass, class_descendants_recursive, v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
class_descendants(VALUE klass, bool immediate_only)
|
|
|
|
{
|
|
|
|
struct subclass_traverse_data data = { Qfalse, 0, -1, immediate_only };
|
|
|
|
|
|
|
|
// estimate the count of subclasses
|
|
|
|
rb_class_foreach_subclass(klass, class_descendants_recursive, (VALUE) &data);
|
|
|
|
|
|
|
|
// the following allocation may cause GC which may change the number of subclasses
|
|
|
|
data.buffer = rb_ary_new_capa(data.count);
|
|
|
|
data.maxcount = data.count;
|
|
|
|
data.count = 0;
|
|
|
|
|
|
|
|
size_t gc_count = rb_gc_count();
|
|
|
|
|
|
|
|
// enumerate subclasses
|
|
|
|
rb_class_foreach_subclass(klass, class_descendants_recursive, (VALUE) &data);
|
|
|
|
|
|
|
|
if (gc_count != rb_gc_count()) {
|
|
|
|
rb_bug("GC must not occur during the subclass iteration of Class#descendants");
|
2021-10-26 22:35:21 +03:00
|
|
|
}
|
2021-10-28 15:07:11 +03:00
|
|
|
|
|
|
|
return data.buffer;
|
2021-10-26 22:35:21 +03:00
|
|
|
}
|
|
|
|
|
2021-10-28 15:07:11 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* subclasses -> array
|
|
|
|
*
|
|
|
|
* Returns an array of classes where the receiver is the
|
|
|
|
* direct superclass of the class, excluding singleton classes.
|
|
|
|
* The order of the returned array is not defined.
|
|
|
|
*
|
|
|
|
* class A; end
|
|
|
|
* class B < A; end
|
|
|
|
* class C < B; end
|
|
|
|
* class D < A; end
|
|
|
|
*
|
|
|
|
* A.subclasses #=> [D, B]
|
|
|
|
* B.subclasses #=> [C]
|
|
|
|
* C.subclasses #=> []
|
|
|
|
*/
|
2021-11-02 21:59:17 +03:00
|
|
|
|
2021-10-28 15:07:11 +03:00
|
|
|
VALUE
|
|
|
|
rb_class_subclasses(VALUE klass)
|
|
|
|
{
|
|
|
|
return class_descendants(klass, true);
|
2021-10-26 22:35:21 +03:00
|
|
|
}
|
|
|
|
|
2016-09-07 10:35:45 +03:00
|
|
|
static void
|
|
|
|
ins_methods_push(st_data_t name, st_data_t ary)
|
2003-05-02 12:24:43 +04:00
|
|
|
{
|
2016-09-07 10:35:45 +03:00
|
|
|
rb_ary_push((VALUE)ary, ID2SYM((ID)name));
|
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2016-09-07 10:35:45 +03:00
|
|
|
static int
|
|
|
|
ins_methods_i(st_data_t name, st_data_t type, st_data_t ary)
|
|
|
|
{
|
|
|
|
switch ((rb_method_visibility_t)type) {
|
2015-06-03 04:39:16 +03:00
|
|
|
case METHOD_VISI_UNDEF:
|
|
|
|
case METHOD_VISI_PRIVATE:
|
2016-09-07 10:35:45 +03:00
|
|
|
break;
|
|
|
|
default: /* everything but private */
|
|
|
|
ins_methods_push(name, ary);
|
2003-05-02 12:24:43 +04:00
|
|
|
break;
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2003-05-02 12:24:43 +04:00
|
|
|
static int
|
2021-03-21 00:57:30 +03:00
|
|
|
ins_methods_type_i(st_data_t name, st_data_t type, st_data_t ary, rb_method_visibility_t visi)
|
2003-05-02 12:24:43 +04:00
|
|
|
{
|
2021-03-21 00:57:30 +03:00
|
|
|
if ((rb_method_visibility_t)type == visi) {
|
2016-09-07 10:35:45 +03:00
|
|
|
ins_methods_push(name, ary);
|
|
|
|
}
|
|
|
|
return ST_CONTINUE;
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
|
2021-03-21 00:57:30 +03:00
|
|
|
static int
|
|
|
|
ins_methods_prot_i(st_data_t name, st_data_t type, st_data_t ary)
|
|
|
|
{
|
|
|
|
return ins_methods_type_i(name, type, ary, METHOD_VISI_PROTECTED);
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
static int
|
2011-06-04 07:49:50 +04:00
|
|
|
ins_methods_priv_i(st_data_t name, st_data_t type, st_data_t ary)
|
1998-01-16 15:19:22 +03:00
|
|
|
{
|
2021-03-21 00:57:30 +03:00
|
|
|
return ins_methods_type_i(name, type, ary, METHOD_VISI_PRIVATE);
|
2003-05-02 12:24:43 +04:00
|
|
|
}
|
2002-10-30 11:04:32 +03:00
|
|
|
|
2003-05-02 12:24:43 +04:00
|
|
|
static int
|
2011-06-04 07:49:50 +04:00
|
|
|
ins_methods_pub_i(st_data_t name, st_data_t type, st_data_t ary)
|
2003-05-02 12:24:43 +04:00
|
|
|
{
|
2021-03-21 00:57:30 +03:00
|
|
|
return ins_methods_type_i(name, type, ary, METHOD_VISI_PUBLIC);
|
2002-10-30 11:04:32 +03:00
|
|
|
}
|
|
|
|
|
2022-06-06 19:57:32 +03:00
|
|
|
static int
|
|
|
|
ins_methods_undef_i(st_data_t name, st_data_t type, st_data_t ary)
|
|
|
|
{
|
|
|
|
if ((rb_method_visibility_t)type == METHOD_VISI_UNDEF) {
|
|
|
|
ins_methods_push(name, ary);
|
|
|
|
}
|
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2015-02-04 10:45:29 +03:00
|
|
|
struct method_entry_arg {
|
|
|
|
st_table *list;
|
|
|
|
int recur;
|
|
|
|
};
|
|
|
|
|
2015-08-12 11:43:55 +03:00
|
|
|
static enum rb_id_table_iterator_result
|
|
|
|
method_entry_i(ID key, VALUE value, void *data)
|
2002-10-30 11:04:32 +03:00
|
|
|
{
|
2011-06-04 07:49:50 +04:00
|
|
|
const rb_method_entry_t *me = (const rb_method_entry_t *)value;
|
2015-02-04 10:45:29 +03:00
|
|
|
struct method_entry_arg *arg = (struct method_entry_arg *)data;
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_method_visibility_t type;
|
1998-01-16 15:19:22 +03:00
|
|
|
|
2015-06-03 22:51:38 +03:00
|
|
|
if (me->def->type == VM_METHOD_TYPE_REFINED) {
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
VALUE owner = me->owner;
|
|
|
|
me = rb_resolve_refined_method(Qnil, me);
|
2015-08-12 11:59:27 +03:00
|
|
|
if (!me) return ID_TABLE_CONTINUE;
|
|
|
|
if (!arg->recur && me->owner != owner) return ID_TABLE_CONTINUE;
|
2013-09-10 07:39:31 +04:00
|
|
|
}
|
2017-05-19 01:59:38 +03:00
|
|
|
if (!st_is_member(arg->list, key)) {
|
2009-08-28 06:45:41 +04:00
|
|
|
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
2015-06-03 04:39:16 +03:00
|
|
|
type = METHOD_VISI_UNDEF; /* none */
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
else {
|
2015-06-06 13:19:48 +03:00
|
|
|
type = METHOD_ENTRY_VISI(me);
|
2021-09-01 12:45:03 +03:00
|
|
|
RUBY_ASSERT(type != METHOD_VISI_UNDEF);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2015-06-05 16:39:59 +03:00
|
|
|
st_add_direct(arg->list, key, (st_data_t)type);
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
2015-08-12 11:59:27 +03:00
|
|
|
return ID_TABLE_CONTINUE;
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
|
2019-01-09 17:04:21 +03:00
|
|
|
static void
|
|
|
|
add_instance_method_list(VALUE mod, struct method_entry_arg *me_arg)
|
|
|
|
{
|
|
|
|
struct rb_id_table *m_tbl = RCLASS_M_TBL(mod);
|
|
|
|
if (!m_tbl) return;
|
|
|
|
rb_id_table_foreach(m_tbl, method_entry_i, me_arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
particular_class_p(VALUE mod)
|
|
|
|
{
|
|
|
|
if (!mod) return false;
|
|
|
|
if (FL_TEST(mod, FL_SINGLETON)) return true;
|
|
|
|
if (BUILTIN_TYPE(mod) == T_ICLASS) return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2003-06-25 11:12:10 +04:00
|
|
|
static VALUE
|
2014-06-18 10:16:39 +04:00
|
|
|
class_instance_method_list(int argc, const VALUE *argv, VALUE mod, int obj, int (*func) (st_data_t, st_data_t, st_data_t))
|
1998-01-16 15:19:22 +03:00
|
|
|
{
|
2003-06-26 16:34:51 +04:00
|
|
|
VALUE ary;
|
2018-12-05 04:09:44 +03:00
|
|
|
int recur = TRUE, prepended = 0;
|
2015-02-04 10:45:29 +03:00
|
|
|
struct method_entry_arg me_arg;
|
1998-01-16 15:19:22 +03:00
|
|
|
|
2018-12-05 04:09:44 +03:00
|
|
|
if (rb_check_arity(argc, 0, 1)) recur = RTEST(argv[0]);
|
2003-06-26 16:34:51 +04:00
|
|
|
|
2019-01-09 17:04:21 +03:00
|
|
|
me_arg.list = st_init_numtable();
|
|
|
|
me_arg.recur = recur;
|
|
|
|
|
|
|
|
if (obj) {
|
|
|
|
for (; particular_class_p(mod); mod = RCLASS_SUPER(mod)) {
|
|
|
|
add_instance_method_list(mod, &me_arg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-28 04:39:52 +04:00
|
|
|
if (!recur && RCLASS_ORIGIN(mod) != mod) {
|
|
|
|
mod = RCLASS_ORIGIN(mod);
|
|
|
|
prepended = 1;
|
|
|
|
}
|
|
|
|
|
2007-09-28 10:21:46 +04:00
|
|
|
for (; mod; mod = RCLASS_SUPER(mod)) {
|
2019-01-09 17:04:21 +03:00
|
|
|
add_instance_method_list(mod, &me_arg);
|
2012-06-28 04:39:52 +04:00
|
|
|
if (BUILTIN_TYPE(mod) == T_ICLASS && !prepended) continue;
|
2003-06-26 16:34:51 +04:00
|
|
|
if (!recur) break;
|
|
|
|
}
|
2019-10-22 02:18:37 +03:00
|
|
|
ary = rb_ary_new2(me_arg.list->num_entries);
|
2015-02-04 10:45:29 +03:00
|
|
|
st_foreach(me_arg.list, func, ary);
|
|
|
|
st_free_table(me_arg.list);
|
2003-06-26 16:34:51 +04:00
|
|
|
|
|
|
|
return ary;
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
|
2003-12-28 09:33:07 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* mod.instance_methods(include_super=true) -> array
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2010-06-22 08:52:03 +04:00
|
|
|
* Returns an array containing the names of the public and protected instance
|
|
|
|
* methods in the receiver. For a module, these are the public and protected methods;
|
2014-05-25 04:43:14 +04:00
|
|
|
* for a class, they are the instance (not singleton) methods. If the optional
|
|
|
|
* parameter is <code>false</code>, the methods of any ancestors are not included.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-28 09:33:07 +03:00
|
|
|
* module A
|
|
|
|
* def method1() end
|
|
|
|
* end
|
|
|
|
* class B
|
2014-05-25 04:43:14 +04:00
|
|
|
* include A
|
2003-12-28 09:33:07 +03:00
|
|
|
* def method2() end
|
|
|
|
* end
|
|
|
|
* class C < B
|
|
|
|
* def method3() end
|
|
|
|
* end
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2014-05-25 04:43:14 +04:00
|
|
|
* A.instance_methods(false) #=> [:method1]
|
|
|
|
* B.instance_methods(false) #=> [:method2]
|
|
|
|
* B.instance_methods(true).include?(:method1) #=> true
|
|
|
|
* C.instance_methods(false) #=> [:method3]
|
|
|
|
* C.instance_methods.include?(:method2) #=> true
|
2003-12-28 09:33:07 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE
|
2014-06-18 10:16:39 +04:00
|
|
|
rb_class_instance_methods(int argc, const VALUE *argv, VALUE mod)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2010-06-17 20:58:25 +04:00
|
|
|
return class_instance_method_list(argc, argv, mod, 0, ins_methods_i);
|
2003-06-25 11:12:10 +04:00
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
|
2003-12-28 09:33:07 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* mod.protected_instance_methods(include_super=true) -> array
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-28 09:33:07 +03:00
|
|
|
* Returns a list of the protected instance methods defined in
|
2014-05-25 04:43:14 +04:00
|
|
|
* <i>mod</i>. If the optional parameter is <code>false</code>, the
|
|
|
|
* methods of any ancestors are not included.
|
2003-12-28 09:33:07 +03:00
|
|
|
*/
|
|
|
|
|
2003-06-25 11:12:10 +04:00
|
|
|
VALUE
|
2014-06-18 10:16:39 +04:00
|
|
|
rb_class_protected_instance_methods(int argc, const VALUE *argv, VALUE mod)
|
2003-06-25 11:12:10 +04:00
|
|
|
{
|
2010-06-17 20:58:25 +04:00
|
|
|
return class_instance_method_list(argc, argv, mod, 0, ins_methods_prot_i);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2003-12-28 09:33:07 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* mod.private_instance_methods(include_super=true) -> array
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-28 09:33:07 +03:00
|
|
|
* Returns a list of the private instance methods defined in
|
2014-05-25 04:43:14 +04:00
|
|
|
* <i>mod</i>. If the optional parameter is <code>false</code>, the
|
|
|
|
* methods of any ancestors are not included.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-28 09:33:07 +03:00
|
|
|
* module Mod
|
|
|
|
* def method1() end
|
|
|
|
* private :method1
|
|
|
|
* def method2() end
|
|
|
|
* end
|
2008-03-09 04:04:46 +03:00
|
|
|
* Mod.instance_methods #=> [:method2]
|
|
|
|
* Mod.private_instance_methods #=> [:method1]
|
2003-12-28 09:33:07 +03:00
|
|
|
*/
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE
|
2014-06-18 10:16:39 +04:00
|
|
|
rb_class_private_instance_methods(int argc, const VALUE *argv, VALUE mod)
|
1998-01-16 15:19:22 +03:00
|
|
|
{
|
2010-06-17 20:58:25 +04:00
|
|
|
return class_instance_method_list(argc, argv, mod, 0, ins_methods_priv_i);
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
|
2003-12-28 09:33:07 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* mod.public_instance_methods(include_super=true) -> array
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-28 09:33:07 +03:00
|
|
|
* Returns a list of the public instance methods defined in <i>mod</i>.
|
2014-05-25 04:43:14 +04:00
|
|
|
* If the optional parameter is <code>false</code>, the methods of
|
|
|
|
* any ancestors are not included.
|
2003-12-28 09:33:07 +03:00
|
|
|
*/
|
|
|
|
|
2002-10-30 11:04:32 +03:00
|
|
|
VALUE
|
2014-06-18 10:16:39 +04:00
|
|
|
rb_class_public_instance_methods(int argc, const VALUE *argv, VALUE mod)
|
2002-10-30 11:04:32 +03:00
|
|
|
{
|
2010-06-17 20:58:25 +04:00
|
|
|
return class_instance_method_list(argc, argv, mod, 0, ins_methods_pub_i);
|
|
|
|
}
|
|
|
|
|
2022-06-06 19:57:32 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* mod.undefined_instance_methods -> array
|
|
|
|
*
|
|
|
|
* Returns a list of the undefined instance methods defined in <i>mod</i>.
|
|
|
|
* The undefined methods of any ancestors are not included.
|
|
|
|
*/
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_class_undefined_instance_methods(VALUE mod)
|
|
|
|
{
|
|
|
|
VALUE include_super = Qfalse;
|
|
|
|
return class_instance_method_list(1, &include_super, mod, 0, ins_methods_undef_i);
|
|
|
|
}
|
|
|
|
|
2010-06-17 20:58:25 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2013-04-24 08:47:31 +04:00
|
|
|
* obj.methods(regular=true) -> array
|
2010-06-17 20:58:25 +04:00
|
|
|
*
|
2010-06-22 08:52:03 +04:00
|
|
|
* Returns a list of the names of public and protected methods of
|
2010-06-17 20:58:25 +04:00
|
|
|
* <i>obj</i>. This will include all the methods accessible in
|
|
|
|
* <i>obj</i>'s ancestors.
|
2014-05-25 04:43:14 +04:00
|
|
|
* If the optional parameter is <code>false</code>, it
|
2019-01-04 11:22:27 +03:00
|
|
|
* returns an array of <i>obj</i>'s public and protected singleton methods,
|
2013-04-24 08:47:31 +04:00
|
|
|
* the array will not include methods in modules included in <i>obj</i>.
|
2010-06-17 20:58:25 +04:00
|
|
|
*
|
|
|
|
* class Klass
|
2011-03-07 11:44:45 +03:00
|
|
|
* def klass_method()
|
2010-06-17 20:58:25 +04:00
|
|
|
* end
|
|
|
|
* end
|
|
|
|
* k = Klass.new
|
2011-03-07 11:44:45 +03:00
|
|
|
* k.methods[0..9] #=> [:klass_method, :nil?, :===,
|
|
|
|
* # :==~, :!, :eql?
|
|
|
|
* # :hash, :<=>, :class, :singleton_class]
|
2014-05-25 04:43:14 +04:00
|
|
|
* k.methods.length #=> 56
|
2013-04-24 08:47:31 +04:00
|
|
|
*
|
|
|
|
* k.methods(false) #=> []
|
|
|
|
* def k.singleton_method; end
|
|
|
|
* k.methods(false) #=> [:singleton_method]
|
|
|
|
*
|
|
|
|
* module M123; def m123; end end
|
|
|
|
* k.extend M123
|
|
|
|
* k.methods(false) #=> [:singleton_method]
|
2010-06-17 20:58:25 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
VALUE
|
2014-06-18 10:16:39 +04:00
|
|
|
rb_obj_methods(int argc, const VALUE *argv, VALUE obj)
|
2010-06-17 20:58:25 +04:00
|
|
|
{
|
2014-01-25 05:55:44 +04:00
|
|
|
rb_check_arity(argc, 0, 1);
|
|
|
|
if (argc > 0 && !RTEST(argv[0])) {
|
2010-06-17 20:58:25 +04:00
|
|
|
return rb_obj_singleton_methods(argc, argv, obj);
|
|
|
|
}
|
2014-01-25 05:55:44 +04:00
|
|
|
return class_instance_method_list(argc, argv, CLASS_OF(obj), 1, ins_methods_i);
|
2010-06-17 20:58:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* obj.protected_methods(all=true) -> array
|
|
|
|
*
|
|
|
|
* Returns the list of protected methods accessible to <i>obj</i>. If
|
|
|
|
* the <i>all</i> parameter is set to <code>false</code>, only those methods
|
|
|
|
* in the receiver will be listed.
|
|
|
|
*/
|
|
|
|
|
|
|
|
VALUE
|
2014-06-18 10:16:39 +04:00
|
|
|
rb_obj_protected_methods(int argc, const VALUE *argv, VALUE obj)
|
2010-06-17 20:58:25 +04:00
|
|
|
{
|
|
|
|
return class_instance_method_list(argc, argv, CLASS_OF(obj), 1, ins_methods_prot_i);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* obj.private_methods(all=true) -> array
|
|
|
|
*
|
|
|
|
* Returns the list of private methods accessible to <i>obj</i>. If
|
|
|
|
* the <i>all</i> parameter is set to <code>false</code>, only those methods
|
|
|
|
* in the receiver will be listed.
|
|
|
|
*/
|
|
|
|
|
|
|
|
VALUE
|
2014-06-18 10:16:39 +04:00
|
|
|
rb_obj_private_methods(int argc, const VALUE *argv, VALUE obj)
|
2010-06-17 20:58:25 +04:00
|
|
|
{
|
|
|
|
return class_instance_method_list(argc, argv, CLASS_OF(obj), 1, ins_methods_priv_i);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* obj.public_methods(all=true) -> array
|
|
|
|
*
|
|
|
|
* Returns the list of public methods accessible to <i>obj</i>. If
|
|
|
|
* the <i>all</i> parameter is set to <code>false</code>, only those methods
|
|
|
|
* in the receiver will be listed.
|
|
|
|
*/
|
|
|
|
|
|
|
|
VALUE
|
2014-06-18 10:16:39 +04:00
|
|
|
rb_obj_public_methods(int argc, const VALUE *argv, VALUE obj)
|
2010-06-17 20:58:25 +04:00
|
|
|
{
|
|
|
|
return class_instance_method_list(argc, argv, CLASS_OF(obj), 1, ins_methods_pub_i);
|
2002-10-30 11:04:32 +03:00
|
|
|
}
|
|
|
|
|
2003-12-28 09:33:07 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* obj.singleton_methods(all=true) -> array
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-28 09:33:07 +03:00
|
|
|
* Returns an array of the names of singleton methods for <i>obj</i>.
|
|
|
|
* If the optional <i>all</i> parameter is true, the list will include
|
|
|
|
* methods in modules included in <i>obj</i>.
|
2010-06-22 08:52:03 +04:00
|
|
|
* Only public and protected singleton methods are returned.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-28 09:33:07 +03:00
|
|
|
* module Other
|
|
|
|
* def three() end
|
|
|
|
* end
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-28 09:33:07 +03:00
|
|
|
* class Single
|
|
|
|
* def Single.four() end
|
|
|
|
* end
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-28 09:33:07 +03:00
|
|
|
* a = Single.new
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-28 09:33:07 +03:00
|
|
|
* def a.one()
|
2004-05-12 06:51:54 +04:00
|
|
|
* end
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-28 09:33:07 +03:00
|
|
|
* class << a
|
|
|
|
* include Other
|
|
|
|
* def two()
|
2004-05-12 06:51:54 +04:00
|
|
|
* end
|
2003-12-28 09:33:07 +03:00
|
|
|
* end
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2008-03-09 04:04:46 +03:00
|
|
|
* Single.singleton_methods #=> [:four]
|
|
|
|
* a.singleton_methods(false) #=> [:two, :one]
|
|
|
|
* a.singleton_methods #=> [:two, :one, :three]
|
2003-12-28 09:33:07 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE
|
2014-06-18 10:16:39 +04:00
|
|
|
rb_obj_singleton_methods(int argc, const VALUE *argv, VALUE obj)
|
1998-01-16 15:19:22 +03:00
|
|
|
{
|
2018-12-05 04:09:44 +03:00
|
|
|
VALUE ary, klass, origin;
|
2015-02-04 10:45:29 +03:00
|
|
|
struct method_entry_arg me_arg;
|
2015-08-12 11:43:55 +03:00
|
|
|
struct rb_id_table *mtbl;
|
2018-12-05 04:09:44 +03:00
|
|
|
int recur = TRUE;
|
1998-01-16 15:19:22 +03:00
|
|
|
|
2018-12-05 04:09:44 +03:00
|
|
|
if (rb_check_arity(argc, 0, 1)) recur = RTEST(argv[0]);
|
2019-07-08 03:58:25 +03:00
|
|
|
if (RB_TYPE_P(obj, T_CLASS) && FL_TEST(obj, FL_SINGLETON)) {
|
|
|
|
rb_singleton_class(obj);
|
|
|
|
}
|
1998-01-16 15:19:22 +03:00
|
|
|
klass = CLASS_OF(obj);
|
2013-03-13 10:13:08 +04:00
|
|
|
origin = RCLASS_ORIGIN(klass);
|
2015-02-04 10:45:29 +03:00
|
|
|
me_arg.list = st_init_numtable();
|
2018-12-05 04:09:44 +03:00
|
|
|
me_arg.recur = recur;
|
2003-08-02 00:16:53 +04:00
|
|
|
if (klass && FL_TEST(klass, FL_SINGLETON)) {
|
2015-08-12 11:43:55 +03:00
|
|
|
if ((mtbl = RCLASS_M_TBL(origin)) != 0) rb_id_table_foreach(mtbl, method_entry_i, &me_arg);
|
2007-09-28 10:21:46 +04:00
|
|
|
klass = RCLASS_SUPER(klass);
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
2018-12-05 04:09:44 +03:00
|
|
|
if (recur) {
|
2011-09-29 15:07:45 +04:00
|
|
|
while (klass && (FL_TEST(klass, FL_SINGLETON) || RB_TYPE_P(klass, T_ICLASS))) {
|
2015-08-12 11:43:55 +03:00
|
|
|
if (klass != origin && (mtbl = RCLASS_M_TBL(klass)) != 0) rb_id_table_foreach(mtbl, method_entry_i, &me_arg);
|
2007-09-28 10:21:46 +04:00
|
|
|
klass = RCLASS_SUPER(klass);
|
2001-05-30 13:12:34 +04:00
|
|
|
}
|
|
|
|
}
|
2019-10-22 02:18:37 +03:00
|
|
|
ary = rb_ary_new2(me_arg.list->num_entries);
|
2015-02-04 10:45:29 +03:00
|
|
|
st_foreach(me_arg.list, ins_methods_i, ary);
|
|
|
|
st_free_table(me_arg.list);
|
1998-01-16 15:19:22 +03:00
|
|
|
|
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2009-08-29 17:39:44 +04:00
|
|
|
/*!
|
|
|
|
* \}
|
|
|
|
*/
|
|
|
|
/*!
|
2020-12-21 08:43:55 +03:00
|
|
|
* \addtogroup defmethod
|
2009-08-29 17:39:44 +04:00
|
|
|
* \{
|
|
|
|
*/
|
|
|
|
|
2019-08-29 04:40:40 +03:00
|
|
|
#ifdef rb_define_method_id
|
|
|
|
#undef rb_define_method_id
|
|
|
|
#endif
|
1998-01-16 15:13:05 +03:00
|
|
|
void
|
2009-07-15 18:59:41 +04:00
|
|
|
rb_define_method_id(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_add_method_cfunc(klass, mid, func, argc, METHOD_VISI_PUBLIC);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
drop-in type check for rb_define_method
The rb_define_method function takes a pointer to ANYARGS-ed functions,
which in fact varies 18 different prototypes. We still need to
preserve ANYARGS for storages but why not check the consistencies if
possible.
Q&As:
Q: Where did the magic number "18" came from in the description above?
A: Count the case branch of vm_method.c:call_cfunc_invoker_func().
Note also that the 18 branches has lasted for at least 25 years.
See also 200e0ee2fd3c1c006c528874a88f684447215524.
Q: What is this __weakref__ thing?
A: That is a kind of function overloading mechanism that GCC provides.
In this case for instance rb_define_method0 is an alias of
rb_define_method, with a strong type.
Q: What is this __transparent_union__ thing?
A: That is another kind of function overloading mechanism that GCC
provides. In this case the attributed function pointer is either
VALUE(*)(int,VALUE*,VALUE) or VALUE(*)(int,const VALUE*,VALUE).
This is better than void* or ANYARGS because we can reject all
other possibilities than the two.
Q: What does this rb_define_method macro mean?
A: It selects appropriate alias of the rb_define_method function,
depending on the arity.
Q: Why the prototype change of rb_f_notimplement?
A: Function pointer to rb_f_notimplement is special cased in
vm_method.c:rb_add_method_cfunc(). That should be handled by the
__builtin_choose_expr chain inside of rb_define_method macro
expansion. In order to do so, comparison like (func ==
rb_f_notimplement) is inappropriate for __builtin_choose_expr's
expression (which must be a compile-time integer constant but the
address of rb_f_notimplement is not fixed until the linker). So
instead we are using __builtin_types_compatible_p, and in doing so
we need to distinguish rb_f_notimplement from others, by type.
2019-08-28 11:11:23 +03:00
|
|
|
#ifdef rb_define_method
|
|
|
|
#undef rb_define_method
|
|
|
|
#endif
|
1998-01-16 15:13:05 +03:00
|
|
|
void
|
2005-10-20 06:56:22 +04:00
|
|
|
rb_define_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_add_method_cfunc(klass, rb_intern(name), func, argc, METHOD_VISI_PUBLIC);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2019-08-29 04:45:09 +03:00
|
|
|
#ifdef rb_define_protected_method
|
|
|
|
#undef rb_define_protected_method
|
|
|
|
#endif
|
1998-01-16 15:13:05 +03:00
|
|
|
void
|
2005-10-20 06:56:22 +04:00
|
|
|
rb_define_protected_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_add_method_cfunc(klass, rb_intern(name), func, argc, METHOD_VISI_PROTECTED);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2019-08-29 04:57:48 +03:00
|
|
|
#ifdef rb_define_private_method
|
|
|
|
#undef rb_define_private_method
|
|
|
|
#endif
|
1998-01-16 15:13:05 +03:00
|
|
|
void
|
2005-10-20 06:56:22 +04:00
|
|
|
rb_define_private_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_add_method_cfunc(klass, rb_intern(name), func, argc, METHOD_VISI_PRIVATE);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_undef_method(VALUE klass, const char *name)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_add_method(klass, rb_intern(name), VM_METHOD_TYPE_UNDEF, 0, METHOD_VISI_UNDEF);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2016-10-24 04:49:52 +03:00
|
|
|
static enum rb_id_table_iterator_result
|
|
|
|
undef_method_i(ID name, VALUE value, void *data)
|
|
|
|
{
|
|
|
|
VALUE klass = (VALUE)data;
|
|
|
|
rb_add_method(klass, name, VM_METHOD_TYPE_UNDEF, 0, METHOD_VISI_UNDEF);
|
|
|
|
return ID_TABLE_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_undef_methods_from(VALUE klass, VALUE super)
|
|
|
|
{
|
|
|
|
struct rb_id_table *mtbl = RCLASS_M_TBL(super);
|
|
|
|
if (mtbl) {
|
|
|
|
rb_id_table_foreach(mtbl, undef_method_i, (void *)klass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-29 17:39:44 +04:00
|
|
|
/*!
|
|
|
|
* \}
|
|
|
|
*/
|
|
|
|
/*!
|
|
|
|
* \addtogroup class
|
|
|
|
* \{
|
|
|
|
*/
|
|
|
|
|
2012-08-06 19:31:13 +04:00
|
|
|
static inline VALUE
|
|
|
|
special_singleton_class_of(VALUE obj)
|
|
|
|
{
|
2020-06-12 06:35:45 +03:00
|
|
|
switch (obj) {
|
|
|
|
case Qnil: return rb_cNilClass;
|
|
|
|
case Qfalse: return rb_cFalseClass;
|
|
|
|
case Qtrue: return rb_cTrueClass;
|
|
|
|
default: return Qnil;
|
|
|
|
}
|
2012-08-06 19:31:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_special_singleton_class(VALUE obj)
|
|
|
|
{
|
|
|
|
return special_singleton_class_of(obj);
|
|
|
|
}
|
2009-08-29 17:39:44 +04:00
|
|
|
|
|
|
|
/*!
|
2009-08-31 09:55:57 +04:00
|
|
|
* \internal
|
|
|
|
* Returns the singleton class of \a obj. Creates it if necessary.
|
2009-08-29 17:39:44 +04:00
|
|
|
*
|
2009-08-31 09:55:57 +04:00
|
|
|
* \note DO NOT expose the returned singleton class to
|
|
|
|
* outside of class.c.
|
2010-05-29 22:51:39 +04:00
|
|
|
* Use \ref rb_singleton_class instead for
|
2009-08-31 09:55:57 +04:00
|
|
|
* consistency of the metaclass hierarchy.
|
2009-08-29 17:39:44 +04:00
|
|
|
*/
|
2009-08-31 09:55:57 +04:00
|
|
|
static VALUE
|
|
|
|
singleton_class_of(VALUE obj)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-12-14 09:50:43 +03:00
|
|
|
VALUE klass;
|
2000-03-07 11:37:59 +03:00
|
|
|
|
2020-06-11 07:53:16 +03:00
|
|
|
switch (TYPE(obj)) {
|
|
|
|
case T_FIXNUM:
|
|
|
|
case T_BIGNUM:
|
|
|
|
case T_FLOAT:
|
|
|
|
case T_SYMBOL:
|
1999-08-13 09:45:20 +04:00
|
|
|
rb_raise(rb_eTypeError, "can't define singleton");
|
2020-06-11 07:53:16 +03:00
|
|
|
|
|
|
|
case T_FALSE:
|
|
|
|
case T_TRUE:
|
|
|
|
case T_NIL:
|
2012-08-06 19:31:13 +04:00
|
|
|
klass = special_singleton_class_of(obj);
|
|
|
|
if (NIL_P(klass))
|
|
|
|
rb_bug("unknown immediate %p", (void *)obj);
|
|
|
|
return klass;
|
2020-06-11 07:53:16 +03:00
|
|
|
|
|
|
|
case T_STRING:
|
|
|
|
if (FL_TEST_RAW(obj, RSTRING_FSTR)) {
|
|
|
|
rb_raise(rb_eTypeError, "can't define singleton");
|
|
|
|
}
|
2012-10-27 06:10:53 +04:00
|
|
|
}
|
2000-05-01 13:42:38 +04:00
|
|
|
|
2022-02-19 15:33:53 +03:00
|
|
|
klass = METACLASS_OF(obj);
|
2014-09-13 17:07:04 +04:00
|
|
|
if (!(FL_TEST(klass, FL_SINGLETON) &&
|
2020-11-12 21:19:41 +03:00
|
|
|
rb_attr_get(klass, id_attached) == obj)) {
|
2016-09-12 18:40:09 +03:00
|
|
|
rb_serial_t serial = RCLASS_SERIAL(klass);
|
2014-09-13 17:07:04 +04:00
|
|
|
klass = rb_make_metaclass(obj, klass);
|
2016-09-12 18:40:09 +03:00
|
|
|
RCLASS_SERIAL(klass) = serial;
|
1999-12-14 09:50:43 +03:00
|
|
|
}
|
* test/ruby/test_metaclass.rb: new test case for metaclass hierarchy.
* class.c (make_metametaclass): new function. extracted from
rb_make_metaclass.
* class.c (rb_make_metaclass): uses make_metametaclass when called for a
metaclass.
* class.c (rb_singleton_class): creates a meta^(n+2)-class in
addition to a meta^(n+1)-class when called for a meta^(n)-class.
This is because the returned meta^(n+1) class must acts as an instance of
Class, metaclass of Class, ..., meta^(n+1)-class of Class,
Module, metaclass of Module, ..., meta^(n+1)-class of Module,
Object, metaclass of Object, ..., meta^(n+2)-class of Object,
BasicObject, metaclass of BasicObject, ..., meta^(n+2)-class of
and BasicObject even when Class, Module, Object or BasicObject has
not have its meta^(i)-class yet.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@20747 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-12-15 09:23:43 +03:00
|
|
|
|
2016-11-12 09:12:12 +03:00
|
|
|
RB_FL_SET_RAW(klass, RB_OBJ_FROZEN_RAW(obj));
|
1999-12-14 09:50:43 +03:00
|
|
|
|
|
|
|
return klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2014-09-19 05:45:45 +04:00
|
|
|
void
|
|
|
|
rb_freeze_singleton_class(VALUE x)
|
|
|
|
{
|
|
|
|
/* should not propagate to meta-meta-class, and so on */
|
|
|
|
if (!(RBASIC(x)->flags & FL_SINGLETON)) {
|
|
|
|
VALUE klass = RBASIC_CLASS(x);
|
2014-09-19 06:40:58 +04:00
|
|
|
if (klass && (klass = RCLASS_ORIGIN(klass)) != 0 &&
|
|
|
|
FL_TEST(klass, (FL_SINGLETON|FL_FREEZE)) == FL_SINGLETON) {
|
2014-09-19 05:45:45 +04:00
|
|
|
OBJ_FREEZE_RAW(klass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-13 09:50:38 +04:00
|
|
|
/*!
|
|
|
|
* Returns the singleton class of \a obj, or nil if obj is not a
|
|
|
|
* singleton object.
|
|
|
|
*
|
|
|
|
* \param obj an arbitrary object.
|
|
|
|
* \return the singleton class or nil.
|
|
|
|
*/
|
|
|
|
VALUE
|
|
|
|
rb_singleton_class_get(VALUE obj)
|
|
|
|
{
|
|
|
|
VALUE klass;
|
|
|
|
|
|
|
|
if (SPECIAL_CONST_P(obj)) {
|
|
|
|
return rb_special_singleton_class(obj);
|
|
|
|
}
|
2022-02-19 15:33:53 +03:00
|
|
|
klass = METACLASS_OF(obj);
|
2013-05-13 09:50:38 +04:00
|
|
|
if (!FL_TEST(klass, FL_SINGLETON)) return Qnil;
|
2020-11-12 21:19:41 +03:00
|
|
|
if (rb_attr_get(klass, id_attached) != obj) return Qnil;
|
2013-05-13 09:50:38 +04:00
|
|
|
return klass;
|
|
|
|
}
|
2009-08-31 09:55:57 +04:00
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_singleton_class(VALUE obj)
|
|
|
|
{
|
|
|
|
VALUE klass = singleton_class_of(obj);
|
|
|
|
|
|
|
|
/* ensures an exposed class belongs to its own eigenclass */
|
2011-09-29 15:07:45 +04:00
|
|
|
if (RB_TYPE_P(obj, T_CLASS)) (void)ENSURE_EIGENCLASS(klass);
|
2009-08-31 09:55:57 +04:00
|
|
|
|
|
|
|
return klass;
|
|
|
|
}
|
|
|
|
|
2009-08-29 17:39:44 +04:00
|
|
|
/*!
|
|
|
|
* \}
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \addtogroup defmethod
|
|
|
|
* \{
|
|
|
|
*/
|
|
|
|
|
2019-08-29 05:47:20 +03:00
|
|
|
#ifdef rb_define_singleton_method
|
|
|
|
#undef rb_define_singleton_method
|
|
|
|
#endif
|
1998-01-16 15:13:05 +03:00
|
|
|
void
|
2005-10-20 06:56:22 +04:00
|
|
|
rb_define_singleton_method(VALUE obj, const char *name, VALUE (*func)(ANYARGS), int argc)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2009-08-31 09:55:57 +04:00
|
|
|
rb_define_method(singleton_class_of(obj), name, func, argc);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2019-08-28 11:48:48 +03:00
|
|
|
#ifdef rb_define_module_function
|
|
|
|
#undef rb_define_module_function
|
|
|
|
#endif
|
1998-01-16 15:13:05 +03:00
|
|
|
void
|
2005-10-20 06:56:22 +04:00
|
|
|
rb_define_module_function(VALUE module, const char *name, VALUE (*func)(ANYARGS), int argc)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
rb_define_private_method(module, name, func, argc);
|
|
|
|
rb_define_singleton_method(module, name, func, argc);
|
|
|
|
}
|
|
|
|
|
2019-08-28 12:19:11 +03:00
|
|
|
#ifdef rb_define_global_function
|
|
|
|
#undef rb_define_global_function
|
|
|
|
#endif
|
1998-01-16 15:13:05 +03:00
|
|
|
void
|
2005-10-20 06:56:22 +04:00
|
|
|
rb_define_global_function(const char *name, VALUE (*func)(ANYARGS), int argc)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_module_function(rb_mKernel, name, func, argc);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_define_alias(VALUE klass, const char *name1, const char *name2)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1998-01-16 15:19:22 +03:00
|
|
|
rb_alias(klass, rb_intern(name1), rb_intern(name2));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_define_attr(VALUE klass, const char *name, int read, int write)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2009-07-18 12:05:32 +04:00
|
|
|
rb_attr(klass, rb_intern(name), read, write, FALSE);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
mjit_compile.c: merge initial JIT compiler
which has been developed by Takashi Kokubun <takashikkbn@gmail> as
YARV-MJIT. Many of its bugs are fixed by wanabe <s.wanabe@gmail.com>.
This JIT compiler is designed to be a safe migration path to introduce
JIT compiler to MRI. So this commit does not include any bytecode
changes or dynamic instruction modifications, which are done in original
MJIT.
This commit even strips off some aggressive optimizations from
YARV-MJIT, and thus it's slower than YARV-MJIT too. But it's still
fairly faster than Ruby 2.5 in some benchmarks (attached below).
Note that this JIT compiler passes `make test`, `make test-all`, `make
test-spec` without JIT, and even with JIT. Not only it's perfectly safe
with JIT disabled because it does not replace VM instructions unlike
MJIT, but also with JIT enabled it stably runs Ruby applications
including Rails applications.
I'm expecting this version as just "initial" JIT compiler. I have many
optimization ideas which are skipped for initial merging, and you may
easily replace this JIT compiler with a faster one by just replacing
mjit_compile.c. `mjit_compile` interface is designed for the purpose.
common.mk: update dependencies for mjit_compile.c.
internal.h: declare `rb_vm_insn_addr2insn` for MJIT.
vm.c: exclude some definitions if `-DMJIT_HEADER` is provided to
compiler. This avoids to include some functions which take a long time
to compile, e.g. vm_exec_core. Some of the purpose is achieved in
transform_mjit_header.rb (see `IGNORED_FUNCTIONS`) but others are
manually resolved for now. Load mjit_helper.h for MJIT header.
mjit_helper.h: New. This is a file used only by JIT-ed code. I'll
refactor `mjit_call_cfunc` later.
vm_eval.c: add some #ifdef switches to skip compiling some functions
like Init_vm_eval.
win32/mkexports.rb: export thread/ec functions, which are used by MJIT.
include/ruby/defines.h: add MJIT_FUNC_EXPORTED macro alis to clarify
that a function is exported only for MJIT.
array.c: export a function used by MJIT.
bignum.c: ditto.
class.c: ditto.
compile.c: ditto.
error.c: ditto.
gc.c: ditto.
hash.c: ditto.
iseq.c: ditto.
numeric.c: ditto.
object.c: ditto.
proc.c: ditto.
re.c: ditto.
st.c: ditto.
string.c: ditto.
thread.c: ditto.
variable.c: ditto.
vm_backtrace.c: ditto.
vm_insnhelper.c: ditto.
vm_method.c: ditto.
I would like to improve maintainability of function exports, but I
believe this way is acceptable as initial merging if we clarify the
new exports are for MJIT (so that we can use them as TODO list to fix)
and add unit tests to detect unresolved symbols.
I'll add unit tests of JIT compilations in succeeding commits.
Author: Takashi Kokubun <takashikkbn@gmail.com>
Contributor: wanabe <s.wanabe@gmail.com>
Part of [Feature #14235]
---
* Known issues
* Code generated by gcc is faster than clang. The benchmark may be worse
in macOS. Following benchmark result is provided by gcc w/ Linux.
* Performance is decreased when Google Chrome is running
* JIT can work on MinGW, but it doesn't improve performance at least
in short running benchmark.
* Currently it doesn't perform well with Rails. We'll try to fix this
before release.
---
* Benchmark reslts
Benchmarked with:
Intel 4.0GHz i7-4790K with 16GB memory under x86-64 Ubuntu 8 Cores
- 2.0.0-p0: Ruby 2.0.0-p0
- r62186: Ruby trunk (early 2.6.0), before MJIT changes
- JIT off: On this commit, but without `--jit` option
- JIT on: On this commit, and with `--jit` option
** Optcarrot fps
Benchmark: https://github.com/mame/optcarrot
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:--------|:--------|:--------|:--------|:--------|
|fps |37.32 |51.46 |51.31 |58.88 |
|vs 2.0.0 |1.00x |1.38x |1.37x |1.58x |
** MJIT benchmarks
Benchmark: https://github.com/benchmark-driver/mjit-benchmarks
(Original: https://github.com/vnmakarov/ruby/tree/rtl_mjit_branch/MJIT-benchmarks)
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:----------|:--------|:--------|:--------|:--------|
|aread |1.00 |1.09 |1.07 |2.19 |
|aref |1.00 |1.13 |1.11 |2.22 |
|aset |1.00 |1.50 |1.45 |2.64 |
|awrite |1.00 |1.17 |1.13 |2.20 |
|call |1.00 |1.29 |1.26 |2.02 |
|const2 |1.00 |1.10 |1.10 |2.19 |
|const |1.00 |1.11 |1.10 |2.19 |
|fannk |1.00 |1.04 |1.02 |1.00 |
|fib |1.00 |1.32 |1.31 |1.84 |
|ivread |1.00 |1.13 |1.12 |2.43 |
|ivwrite |1.00 |1.23 |1.21 |2.40 |
|mandelbrot |1.00 |1.13 |1.16 |1.28 |
|meteor |1.00 |2.97 |2.92 |3.17 |
|nbody |1.00 |1.17 |1.15 |1.49 |
|nest-ntimes|1.00 |1.22 |1.20 |1.39 |
|nest-while |1.00 |1.10 |1.10 |1.37 |
|norm |1.00 |1.18 |1.16 |1.24 |
|nsvb |1.00 |1.16 |1.16 |1.17 |
|red-black |1.00 |1.02 |0.99 |1.12 |
|sieve |1.00 |1.30 |1.28 |1.62 |
|trees |1.00 |1.14 |1.13 |1.19 |
|while |1.00 |1.12 |1.11 |2.41 |
** Discourse's script/bench.rb
Benchmark: https://github.com/discourse/discourse/blob/v1.8.7/script/bench.rb
NOTE: Rails performance was somehow a little degraded with JIT for now.
We should fix this.
(At least I know opt_aref is performing badly in JIT and I have an idea
to fix it. Please wait for the fix.)
*** JIT off
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 17
75: 18
90: 22
99: 29
home_admin:
50: 21
75: 21
90: 27
99: 40
topic_admin:
50: 17
75: 18
90: 22
99: 32
categories:
50: 35
75: 41
90: 43
99: 77
home:
50: 39
75: 46
90: 49
99: 95
topic:
50: 46
75: 52
90: 56
99: 101
*** JIT on
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 19
75: 21
90: 25
99: 33
home_admin:
50: 24
75: 26
90: 30
99: 35
topic_admin:
50: 19
75: 20
90: 25
99: 30
categories:
50: 40
75: 44
90: 48
99: 76
home:
50: 42
75: 48
90: 51
99: 89
topic:
50: 49
75: 55
90: 58
99: 99
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62197 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 14:22:28 +03:00
|
|
|
MJIT_FUNC_EXPORTED VALUE
|
2016-05-22 05:44:54 +03:00
|
|
|
rb_keyword_error_new(const char *error, VALUE keys)
|
|
|
|
{
|
2017-08-19 04:04:15 +03:00
|
|
|
long i = 0, len = RARRAY_LEN(keys);
|
|
|
|
VALUE error_message = rb_sprintf("%s keyword%.*s", error, len > 1, "s");
|
|
|
|
|
|
|
|
if (len > 0) {
|
|
|
|
rb_str_cat_cstr(error_message, ": ");
|
|
|
|
while (1) {
|
2018-10-29 21:00:14 +03:00
|
|
|
const VALUE k = RARRAY_AREF(keys, i);
|
2019-03-18 08:25:47 +03:00
|
|
|
rb_str_append(error_message, rb_inspect(k));
|
2017-08-19 04:04:15 +03:00
|
|
|
if (++i >= len) break;
|
|
|
|
rb_str_cat_cstr(error_message, ", ");
|
|
|
|
}
|
2016-05-22 05:44:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return rb_exc_new_str(rb_eArgError, error_message);
|
|
|
|
}
|
|
|
|
|
|
|
|
NORETURN(static void rb_keyword_error(const char *error, VALUE keys));
|
|
|
|
static void
|
|
|
|
rb_keyword_error(const char *error, VALUE keys)
|
|
|
|
{
|
|
|
|
rb_exc_raise(rb_keyword_error_new(error, keys));
|
|
|
|
}
|
|
|
|
|
|
|
|
NORETURN(static void unknown_keyword_error(VALUE hash, const ID *table, int keywords));
|
|
|
|
static void
|
|
|
|
unknown_keyword_error(VALUE hash, const ID *table, int keywords)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < keywords; i++) {
|
|
|
|
st_data_t key = ID2SYM(table[i]);
|
2018-10-31 01:12:12 +03:00
|
|
|
rb_hash_stlike_delete(hash, &key, NULL);
|
2016-05-22 05:44:54 +03:00
|
|
|
}
|
2017-08-19 03:45:22 +03:00
|
|
|
rb_keyword_error("unknown", rb_hash_keys(hash));
|
2016-05-22 05:44:54 +03:00
|
|
|
}
|
|
|
|
|
2018-08-14 14:58:17 +03:00
|
|
|
|
2016-05-22 05:44:54 +03:00
|
|
|
static int
|
|
|
|
separate_symbol(st_data_t key, st_data_t value, st_data_t arg)
|
|
|
|
{
|
2019-03-11 15:48:33 +03:00
|
|
|
VALUE *kwdhash = (VALUE *)arg;
|
|
|
|
if (!SYMBOL_P(key)) kwdhash++;
|
|
|
|
if (!*kwdhash) *kwdhash = rb_hash_new();
|
|
|
|
rb_hash_aset(*kwdhash, (VALUE)key, (VALUE)value);
|
2016-05-22 05:44:54 +03:00
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_extract_keywords(VALUE *orighash)
|
|
|
|
{
|
2019-03-11 15:48:33 +03:00
|
|
|
VALUE parthash[2] = {0, 0};
|
2016-05-22 05:44:54 +03:00
|
|
|
VALUE hash = *orighash;
|
|
|
|
|
|
|
|
if (RHASH_EMPTY_P(hash)) {
|
|
|
|
*orighash = 0;
|
|
|
|
return hash;
|
|
|
|
}
|
2019-03-11 15:48:33 +03:00
|
|
|
rb_hash_foreach(hash, separate_symbol, (st_data_t)&parthash);
|
|
|
|
*orighash = parthash[1];
|
|
|
|
if (parthash[1] && RBASIC_CLASS(hash) != rb_cHash) {
|
2019-03-11 15:48:34 +03:00
|
|
|
RBASIC_SET_CLASS(parthash[1], RBASIC_CLASS(hash));
|
2017-01-18 06:38:52 +03:00
|
|
|
}
|
2019-03-11 15:48:33 +03:00
|
|
|
return parthash[0];
|
2016-05-22 05:44:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
|
|
|
|
{
|
|
|
|
int i = 0, j;
|
|
|
|
int rest = 0;
|
|
|
|
VALUE missing = Qnil;
|
|
|
|
st_data_t key;
|
|
|
|
|
|
|
|
#define extract_kwarg(keyword, val) \
|
|
|
|
(key = (st_data_t)(keyword), values ? \
|
2019-07-16 02:48:57 +03:00
|
|
|
(rb_hash_stlike_delete(keyword_hash, &key, &(val)) || ((val) = Qundef, 0)) : \
|
|
|
|
rb_hash_stlike_lookup(keyword_hash, key, NULL))
|
2016-05-22 05:44:54 +03:00
|
|
|
|
|
|
|
if (NIL_P(keyword_hash)) keyword_hash = 0;
|
|
|
|
|
|
|
|
if (optional < 0) {
|
|
|
|
rest = 1;
|
|
|
|
optional = -1-optional;
|
|
|
|
}
|
|
|
|
if (required) {
|
|
|
|
for (; i < required; i++) {
|
|
|
|
VALUE keyword = ID2SYM(table[i]);
|
|
|
|
if (keyword_hash) {
|
2019-07-16 03:22:11 +03:00
|
|
|
if (extract_kwarg(keyword, values[i])) {
|
2016-05-22 05:44:54 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (NIL_P(missing)) missing = rb_ary_tmp_new(1);
|
|
|
|
rb_ary_push(missing, keyword);
|
|
|
|
}
|
|
|
|
if (!NIL_P(missing)) {
|
|
|
|
rb_keyword_error("missing", missing);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
j = i;
|
|
|
|
if (optional && keyword_hash) {
|
|
|
|
for (i = 0; i < optional; i++) {
|
2019-07-16 03:22:11 +03:00
|
|
|
if (extract_kwarg(ID2SYM(table[required+i]), values[required+i])) {
|
2016-05-22 05:44:54 +03:00
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!rest && keyword_hash) {
|
2016-12-04 11:50:29 +03:00
|
|
|
if (RHASH_SIZE(keyword_hash) > (unsigned int)(values ? 0 : j)) {
|
2016-05-22 05:44:54 +03:00
|
|
|
unknown_keyword_error(keyword_hash, table, required+optional);
|
|
|
|
}
|
|
|
|
}
|
2019-07-16 02:48:57 +03:00
|
|
|
if (values && !keyword_hash) {
|
2019-07-16 03:22:11 +03:00
|
|
|
for (i = 0; i < required + optional; i++) {
|
|
|
|
values[i] = Qundef;
|
|
|
|
}
|
2019-07-16 02:48:57 +03:00
|
|
|
}
|
2016-05-22 05:44:54 +03:00
|
|
|
return j;
|
|
|
|
#undef extract_kwarg
|
|
|
|
}
|
2016-05-21 17:01:23 +03:00
|
|
|
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
struct rb_scan_args_t {
|
2020-02-03 04:49:17 +03:00
|
|
|
int kw_flag;
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
int n_lead;
|
|
|
|
int n_opt;
|
|
|
|
int n_trail;
|
2020-04-12 17:29:22 +03:00
|
|
|
bool f_var;
|
|
|
|
bool f_hash;
|
|
|
|
bool f_block;
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
2020-02-03 04:49:17 +03:00
|
|
|
rb_scan_args_parse(int kw_flag, const char *fmt, struct rb_scan_args_t *arg)
|
2016-05-21 17:01:23 +03:00
|
|
|
{
|
|
|
|
const char *p = fmt;
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
|
|
|
|
memset(arg, 0, sizeof(*arg));
|
2020-02-03 04:49:17 +03:00
|
|
|
arg->kw_flag = kw_flag;
|
2016-05-21 17:01:23 +03:00
|
|
|
|
|
|
|
if (ISDIGIT(*p)) {
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
arg->n_lead = *p - '0';
|
2016-05-21 17:01:23 +03:00
|
|
|
p++;
|
|
|
|
if (ISDIGIT(*p)) {
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
arg->n_opt = *p - '0';
|
2016-05-21 17:01:23 +03:00
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (*p == '*') {
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
arg->f_var = 1;
|
2016-05-21 17:01:23 +03:00
|
|
|
p++;
|
|
|
|
}
|
2016-05-25 11:13:37 +03:00
|
|
|
if (ISDIGIT(*p)) {
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
arg->n_trail = *p - '0';
|
2016-05-25 11:13:37 +03:00
|
|
|
p++;
|
|
|
|
}
|
2016-05-21 17:01:23 +03:00
|
|
|
if (*p == ':') {
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
arg->f_hash = 1;
|
2016-05-21 17:01:23 +03:00
|
|
|
p++;
|
|
|
|
}
|
|
|
|
if (*p == '&') {
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
arg->f_block = 1;
|
2016-05-21 17:01:23 +03:00
|
|
|
p++;
|
|
|
|
}
|
|
|
|
if (*p != '\0') {
|
|
|
|
rb_fatal("bad scan arg format: %s", fmt);
|
|
|
|
}
|
2020-02-03 04:49:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
rb_scan_args_assign(const struct rb_scan_args_t *arg, int argc, const VALUE *const argv, va_list vargs)
|
|
|
|
{
|
|
|
|
int i, argi = 0;
|
|
|
|
VALUE *var, hash = Qnil;
|
2020-04-12 17:29:22 +03:00
|
|
|
#define rb_scan_args_next_param() va_arg(vargs, VALUE *)
|
|
|
|
const int kw_flag = arg->kw_flag;
|
|
|
|
const int n_lead = arg->n_lead;
|
|
|
|
const int n_opt = arg->n_opt;
|
|
|
|
const int n_trail = arg->n_trail;
|
|
|
|
const int n_mand = n_lead + n_trail;
|
|
|
|
const bool f_var = arg->f_var;
|
|
|
|
const bool f_hash = arg->f_hash;
|
|
|
|
const bool f_block = arg->f_block;
|
|
|
|
|
2020-05-21 06:00:33 +03:00
|
|
|
/* capture an option hash - phase 1: pop from the argv */
|
2020-04-12 17:29:22 +03:00
|
|
|
if (f_hash && argc > 0) {
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
VALUE last = argv[argc - 1];
|
2020-04-12 17:29:22 +03:00
|
|
|
if (rb_scan_args_keyword_p(kw_flag, last)) {
|
2020-02-03 04:49:17 +03:00
|
|
|
hash = rb_hash_dup(last);
|
2019-10-04 22:51:57 +03:00
|
|
|
argc--;
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
}
|
|
|
|
}
|
2016-05-21 17:01:23 +03:00
|
|
|
|
2020-04-12 17:29:22 +03:00
|
|
|
if (argc < n_mand) {
|
2020-02-03 04:49:17 +03:00
|
|
|
goto argc_error;
|
2016-05-21 17:01:23 +03:00
|
|
|
}
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
|
2016-05-21 17:01:23 +03:00
|
|
|
/* capture leading mandatory arguments */
|
2020-05-21 06:00:33 +03:00
|
|
|
for (i = 0; i < n_lead; i++) {
|
2020-04-12 17:29:22 +03:00
|
|
|
var = rb_scan_args_next_param();
|
2020-02-03 04:49:17 +03:00
|
|
|
if (var) *var = argv[argi];
|
2016-05-21 17:01:23 +03:00
|
|
|
argi++;
|
|
|
|
}
|
|
|
|
/* capture optional arguments */
|
2020-05-21 06:00:33 +03:00
|
|
|
for (i = 0; i < n_opt; i++) {
|
2020-04-12 17:29:22 +03:00
|
|
|
var = rb_scan_args_next_param();
|
|
|
|
if (argi < argc - n_trail) {
|
2020-02-03 04:49:17 +03:00
|
|
|
if (var) *var = argv[argi];
|
2016-05-21 17:01:23 +03:00
|
|
|
argi++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (var) *var = Qnil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* capture variable length arguments */
|
2020-04-12 17:29:22 +03:00
|
|
|
if (f_var) {
|
|
|
|
int n_var = argc - argi - n_trail;
|
2016-05-21 17:01:23 +03:00
|
|
|
|
2020-04-12 17:29:22 +03:00
|
|
|
var = rb_scan_args_next_param();
|
2016-05-21 17:01:23 +03:00
|
|
|
if (0 < n_var) {
|
2020-04-12 17:29:22 +03:00
|
|
|
if (var) *var = rb_ary_new_from_values(n_var, &argv[argi]);
|
2016-05-21 17:01:23 +03:00
|
|
|
argi += n_var;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (var) *var = rb_ary_new();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* capture trailing mandatory arguments */
|
2020-05-21 06:00:33 +03:00
|
|
|
for (i = 0; i < n_trail; i++) {
|
2020-04-12 17:29:22 +03:00
|
|
|
var = rb_scan_args_next_param();
|
2020-02-03 04:49:17 +03:00
|
|
|
if (var) *var = argv[argi];
|
2016-05-21 17:01:23 +03:00
|
|
|
argi++;
|
|
|
|
}
|
|
|
|
/* capture an option hash - phase 2: assignment */
|
2020-04-12 17:29:22 +03:00
|
|
|
if (f_hash) {
|
|
|
|
var = rb_scan_args_next_param();
|
2020-02-03 04:49:17 +03:00
|
|
|
if (var) *var = hash;
|
2016-05-21 17:01:23 +03:00
|
|
|
}
|
|
|
|
/* capture iterator block */
|
2020-04-12 17:29:22 +03:00
|
|
|
if (f_block) {
|
|
|
|
var = rb_scan_args_next_param();
|
2016-05-21 17:01:23 +03:00
|
|
|
if (rb_block_given_p()) {
|
|
|
|
*var = rb_block_proc();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*var = Qnil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-21 06:00:33 +03:00
|
|
|
if (argi == argc) {
|
|
|
|
return argc;
|
2020-02-03 04:49:17 +03:00
|
|
|
}
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
|
2020-05-21 06:00:33 +03:00
|
|
|
argc_error:
|
|
|
|
return -(argc + 1);
|
2020-04-12 17:29:22 +03:00
|
|
|
#undef rb_scan_args_next_param
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
}
|
|
|
|
|
2020-02-14 09:38:42 +03:00
|
|
|
static int
|
|
|
|
rb_scan_args_result(const struct rb_scan_args_t *const arg, int argc)
|
|
|
|
{
|
2020-05-21 06:00:33 +03:00
|
|
|
const int n_lead = arg->n_lead;
|
|
|
|
const int n_opt = arg->n_opt;
|
|
|
|
const int n_trail = arg->n_trail;
|
|
|
|
const int n_mand = n_lead + n_trail;
|
|
|
|
const bool f_var = arg->f_var;
|
|
|
|
|
|
|
|
if (argc >= 0) {
|
|
|
|
return argc;
|
2020-02-14 09:38:42 +03:00
|
|
|
}
|
2020-04-12 17:29:22 +03:00
|
|
|
|
2020-05-21 06:00:33 +03:00
|
|
|
argc = -argc - 1;
|
|
|
|
rb_error_arity(argc, n_mand, f_var ? UNLIMITED_ARGUMENTS : n_mand + n_opt);
|
|
|
|
UNREACHABLE_RETURN(-1);
|
2020-02-14 09:38:42 +03:00
|
|
|
}
|
|
|
|
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
#undef rb_scan_args
|
|
|
|
int
|
|
|
|
rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list vargs;
|
|
|
|
struct rb_scan_args_t arg;
|
2020-02-03 04:49:17 +03:00
|
|
|
rb_scan_args_parse(RB_SCAN_ARGS_PASS_CALLED_KEYWORDS, fmt, &arg);
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
va_start(vargs,fmt);
|
2020-02-03 04:49:17 +03:00
|
|
|
argc = rb_scan_args_assign(&arg, argc, argv, vargs);
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
va_end(vargs);
|
2020-02-14 09:38:42 +03:00
|
|
|
return rb_scan_args_result(&arg, argc);
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
}
|
2016-05-21 17:01:23 +03:00
|
|
|
|
2020-02-03 07:07:34 +03:00
|
|
|
#undef rb_scan_args_kw
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
int
|
|
|
|
rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list vargs;
|
|
|
|
struct rb_scan_args_t arg;
|
2020-02-03 04:49:17 +03:00
|
|
|
rb_scan_args_parse(kw_flag, fmt, &arg);
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
va_start(vargs,fmt);
|
2020-02-03 04:49:17 +03:00
|
|
|
argc = rb_scan_args_assign(&arg, argc, argv, vargs);
|
Make rb_scan_args handle keywords more similar to Ruby methods (#2460)
Cfuncs that use rb_scan_args with the : entry suffer similar keyword
argument separation issues that Ruby methods suffer if the cfuncs
accept optional or variable arguments.
This makes the following changes to : handling.
* Treats as **kw, prompting keyword argument separation warnings
if called with a positional hash.
* Do not look for an option hash if empty keywords are provided.
For backwards compatibility, treat an empty keyword splat as a empty
mandatory positional hash argument, but emit a a warning, as this
behavior will be removed in Ruby 3. The argument number check
needs to be moved lower so it can correctly handle an empty
positional argument being added.
* If the last argument is nil and it is necessary to treat it as an option
hash in order to make sure all arguments are processed, continue to
treat the last argument as the option hash. Emit a warning in this case,
as this behavior will be removed in Ruby 3.
* If splitting the keyword hash into two hashes, issue a warning, as we
will not be splitting hashes in Ruby 3.
* If the keyword argument is required to fill a mandatory positional
argument, continue to do so, but emit a warning as this behavior will
be going away in Ruby 3.
* If keyword arguments are provided and the last argument is not a hash,
that indicates something wrong. This can happen if a cfunc is calling
rb_scan_args multiple times, and providing arguments that were not
passed to it from Ruby. Callers need to switch to the new
rb_scan_args_kw function, which allows passing of whether keywords
were provided.
This commit fixes all warnings caused by the changes above.
It switches some function calls to *_kw versions with appropriate
kw_splat flags. If delegating arguments, RB_PASS_CALLED_KEYWORDS
is used. If creating new arguments, RB_PASS_KEYWORDS is used if
the last argument is a hash to be treated as keywords.
In open_key_args in io.c, use rb_scan_args_kw.
In this case, the arguments provided come from another C
function, not Ruby. The last argument may or may not be a hash,
so we can't set keyword argument mode. However, if it is a
hash, we don't want to warn when treating it as keywords.
In Ruby files, make sure to appropriately use keyword splats
or literal keywords when calling Cfuncs that now issue keyword
argument separation warnings through rb_scan_args. Also, make
sure not to pass nil in place of an option hash.
Work around Kernel#warn warnings due to problems in the Rubygems
override of the method. There is an open pull request to fix
these issues in Rubygems, but part of the Rubygems tests for
their override fail on ruby-head due to rb_scan_args not
recognizing empty keyword splats, which this commit fixes.
Implementation wise, adding rb_scan_args_kw is kind of a pain,
because rb_scan_args takes a variable number of arguments.
In order to not duplicate all the code, the function internals need
to be split into two functions taking a va_list, and to avoid passing
in a ton of arguments, a single struct argument is used to handle
the variables previously local to the function.
2019-09-25 21:18:49 +03:00
|
|
|
va_end(vargs);
|
2020-02-14 09:38:42 +03:00
|
|
|
return rb_scan_args_result(&arg, argc);
|
2016-05-21 17:01:23 +03:00
|
|
|
}
|
|
|
|
|
2009-06-29 20:39:28 +04:00
|
|
|
/*!
|
|
|
|
* \}
|
|
|
|
*/
|