Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions class.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,95 @@
#define METACLASS_OF(k) RBASIC(k)->klass
#define SET_METACLASS_OF(k, cls) RBASIC_SET_CLASS(k, cls)

static enum rb_id_table_iterator_result
cvar_table_free_i(VALUE value, void *ctx)
{
xfree((void *)value);
return ID_TABLE_CONTINUE;
}

void
rb_class_classext_free(VALUE klass, rb_classext_t *ext, bool is_prime)
{
struct rb_id_table *tbl;

rb_id_table_free(RCLASSEXT_M_TBL(ext));

if (!RCLASSEXT_SHARED_CONST_TBL(ext) && (tbl = RCLASSEXT_CONST_TBL(ext)) != NULL) {
rb_free_const_table(tbl);
}

if ((tbl = RCLASSEXT_CVC_TBL(ext)) != NULL) {
rb_id_table_foreach_values(tbl, cvar_table_free_i, NULL);
rb_id_table_free(tbl);
}

rb_class_classext_free_subclasses(ext, klass);

if (RCLASSEXT_SUPERCLASSES_WITH_SELF(ext)) {
RUBY_ASSERT(is_prime); // superclasses should only be used on prime
xfree(RCLASSEXT_SUPERCLASSES(ext));
}

if (!is_prime) { // the prime classext will be freed with RClass
xfree(ext);
}
}

void
rb_iclass_classext_free(VALUE klass, rb_classext_t *ext, bool is_prime)
{
if (RCLASSEXT_ICLASS_IS_ORIGIN(ext) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext)) {
/* Method table is not shared for origin iclasses of classes */
rb_id_table_free(RCLASSEXT_M_TBL(ext));
}

if (RCLASSEXT_CALLABLE_M_TBL(ext) != NULL) {
rb_id_table_free(RCLASSEXT_CALLABLE_M_TBL(ext));
}

rb_class_classext_free_subclasses(ext, klass);

if (!is_prime) { // the prime classext will be freed with RClass
xfree(ext);
}
}

struct rb_class_set_namespace_classext_args {
VALUE obj;
rb_classext_t *ext;
};

static int
rb_class_set_namespace_classext_update(st_data_t *key_ptr, st_data_t *val_ptr, st_data_t a, int existing)
{
struct rb_class_set_namespace_classext_args *args = (struct rb_class_set_namespace_classext_args *)a;

if (existing) {
if (BUILTIN_TYPE(args->obj) == T_ICLASS) {
rb_iclass_classext_free(args->obj, (rb_classext_t *)*val_ptr, false);
}
else {
rb_class_classext_free(args->obj, (rb_classext_t *)*val_ptr, false);
}
}

*val_ptr = (st_data_t)args->ext;

return ST_CONTINUE;
}

void
rb_class_set_namespace_classext(VALUE obj, const rb_namespace_t *ns, rb_classext_t *ext)
{
struct rb_class_set_namespace_classext_args args = {
.obj = obj,
.ext = ext,
};

st_update(RCLASS_CLASSEXT_TBL(obj), (st_data_t)ns->ns_object, rb_class_set_namespace_classext_update, (st_data_t)&args);
}

RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state;

struct duplicate_id_tbl_data {
Expand Down
1 change: 1 addition & 0 deletions depend
Original file line number Diff line number Diff line change
Expand Up @@ -9302,6 +9302,7 @@ namespace.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
namespace.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
namespace.$(OBJEXT): {$(VPATH)}config.h
namespace.$(OBJEXT): {$(VPATH)}constant.h
namespace.$(OBJEXT): {$(VPATH)}darray.h
namespace.$(OBJEXT): {$(VPATH)}debug_counter.h
namespace.$(OBJEXT): {$(VPATH)}defines.h
namespace.$(OBJEXT): {$(VPATH)}encoding.h
Expand Down
36 changes: 36 additions & 0 deletions doc/string/scan.rdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
Matches a pattern against +self+:

- If +pattern+ is a Regexp, the pattern used is +pattern+ itself.
- If +pattern+ is a string, the pattern used is <tt>Regexp.quote(pattern)</tt>.

Generates a collection of matching results
and updates {regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:

- If the pattern contains no groups, each result is a matched substring.
- If the pattern contains groups, each result is an array
containing a matched substring for each group.

With no block given, returns an array of the results:

'cruel world'.scan(/\w+/) # => ["cruel", "world"]
'cruel world'.scan(/.../) # => ["cru", "el ", "wor"]
'cruel world'.scan(/(...)/) # => [["cru"], ["el "], ["wor"]]
'cruel world'.scan(/(..)(..)/) # => [["cr", "ue"], ["l ", "wo"]]
'тест'.scan(/../) # => ["те", "ст"]
'こんにちは'.scan(/../) # => ["こん", "にち"]
'abracadabra'.scan('ab') # => ["ab", "ab"]
'abracadabra'.scan('nosuch') # => []

With a block given, calls the block with each result; returns +self+:

'cruel world'.scan(/\w+/) {|w| p w }
# => "cruel"
# => "world"
'cruel world'.scan(/(.)(.)/) {|x, y| p [x, y] }
# => ["c", "r"]
# => ["u", "e"]
# => ["l", " "]
# => ["w", "o"]
# => ["r", "l"]

Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
27 changes: 12 additions & 15 deletions doc/string/scrub.rdoc
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
Returns a copy of +self+ with each invalid byte sequence replaced
by the given +replacement_string+.

With no block given and no argument, replaces each invalid sequence
with the default replacement string
(<tt>"�"</tt> for a Unicode encoding, <tt>'?'</tt> otherwise):
With no block given, replaces each invalid sequence
with the given +default_replacement_string+
(by default, <tt>"�"</tt> for a Unicode encoding, <tt>'?'</tt> otherwise):

s = "foo\x81\x81bar"
s.scrub # => "foo��bar"
"foo\x81\x81bar"scrub # => "foo��bar"
"foo\x81\x81bar".force_encoding('US-ASCII').scrub # => "foo??bar"
"foo\x81\x81bar".scrub('xyzzy') # => "fooxyzzyxyzzybar"

With no block given and argument +replacement_string+ given,
replaces each invalid sequence with that string:
With a block given, calls the block with each invalid sequence,
and replaces that sequence with the return value of the block:

"foo\x81\x81bar".scrub('xyzzy') # => "fooxyzzyxyzzybar"
"foo\x81\x81bar".scrub {|sequence| p sequence; 'XYZZY' } # => "fooXYZZYXYZZYbar"

With a block given, replaces each invalid sequence with the value
of the block:

"foo\x81\x81bar".scrub {|bytes| p bytes; 'XYZZY' }
# => "fooXYZZYXYZZYbar"

Output:
Output :

"\x81"
"\x81"

Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
40 changes: 2 additions & 38 deletions gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1160,13 +1160,6 @@ rb_objspace_data_type_name(VALUE obj)
}
}

static enum rb_id_table_iterator_result
cvar_table_free_i(VALUE value, void *ctx)
{
xfree((void *)value);
return ID_TABLE_CONTINUE;
}

static void
io_fptr_finalize(void *fptr)
{
Expand Down Expand Up @@ -1233,46 +1226,17 @@ struct classext_foreach_args {
static void
classext_free(rb_classext_t *ext, bool is_prime, VALUE namespace, void *arg)
{
struct rb_id_table *tbl;
struct classext_foreach_args *args = (struct classext_foreach_args *)arg;

rb_id_table_free(RCLASSEXT_M_TBL(ext));

if (!RCLASSEXT_SHARED_CONST_TBL(ext) && (tbl = RCLASSEXT_CONST_TBL(ext)) != NULL) {
rb_free_const_table(tbl);
}
if ((tbl = RCLASSEXT_CVC_TBL(ext)) != NULL) {
rb_id_table_foreach_values(tbl, cvar_table_free_i, NULL);
rb_id_table_free(tbl);
}
rb_class_classext_free_subclasses(ext, args->klass);
if (RCLASSEXT_SUPERCLASSES_WITH_SELF(ext)) {
RUBY_ASSERT(is_prime); // superclasses should only be used on prime
xfree(RCLASSEXT_SUPERCLASSES(ext));
}
if (!is_prime) { // the prime classext will be freed with RClass
xfree(ext);
}
rb_class_classext_free(args->klass, ext, is_prime);
}

static void
classext_iclass_free(rb_classext_t *ext, bool is_prime, VALUE namespace, void *arg)
{
struct classext_foreach_args *args = (struct classext_foreach_args *)arg;

if (RCLASSEXT_ICLASS_IS_ORIGIN(ext) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext)) {
/* Method table is not shared for origin iclasses of classes */
rb_id_table_free(RCLASSEXT_M_TBL(ext));
}
if (RCLASSEXT_CALLABLE_M_TBL(ext) != NULL) {
rb_id_table_free(RCLASSEXT_CALLABLE_M_TBL(ext));
}

rb_class_classext_free_subclasses(ext, args->klass);

if (!is_prime) { // the prime classext will be freed with RClass
xfree(ext);
}
rb_iclass_classext_free(args->klass, ext, is_prime);
}

bool
Expand Down
9 changes: 8 additions & 1 deletion internal/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,8 @@ RCLASS_SET_CLASSEXT_TBL(VALUE klass, st_table *tbl)
rb_classext_t * rb_class_duplicate_classext(rb_classext_t *orig, VALUE obj, const rb_namespace_t *ns);
void rb_class_ensure_writable(VALUE obj);

void rb_class_set_namespace_classext(VALUE obj, const rb_namespace_t *ns, rb_classext_t *ext);

static inline int
RCLASS_SET_NAMESPACE_CLASSEXT(VALUE obj, const rb_namespace_t *ns, rb_classext_t *ext)
{
Expand All @@ -332,7 +334,9 @@ RCLASS_SET_NAMESPACE_CLASSEXT(VALUE obj, const rb_namespace_t *ns, rb_classext_t
if (rb_st_table_size(tbl) == 0) {
first_set = 1;
}
rb_st_insert(tbl, (st_data_t)ns->ns_object, (st_data_t)ext);

rb_class_set_namespace_classext(obj, ns, ext);

return first_set;
}

Expand Down Expand Up @@ -515,6 +519,9 @@ void rb_undef_methods_from(VALUE klass, VALUE super);
VALUE rb_class_inherited(VALUE, VALUE);
VALUE rb_keyword_error_new(const char *, VALUE);

void rb_class_classext_free(VALUE klass, rb_classext_t *ext, bool is_prime);
void rb_iclass_classext_free(VALUE klass, rb_classext_t *ext, bool is_prime);

RUBY_SYMBOL_EXPORT_BEGIN

/* for objspace */
Expand Down
27 changes: 25 additions & 2 deletions jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,20 @@
#include "vm_sync.h"
#include "internal/fixnum.h"

// Field offsets for the RObject struct
enum robject_offsets {
enum jit_bindgen_constants {
// Field offsets for the RObject struct
ROBJECT_OFFSET_AS_HEAP_FIELDS = offsetof(struct RObject, as.heap.fields),
ROBJECT_OFFSET_AS_ARY = offsetof(struct RObject, as.ary),

// Field offsets for the RString struct
RUBY_OFFSET_RSTRING_LEN = offsetof(struct RString, len)
};

// Manually bound in rust since this is out-of-range of `int`,
// so this can't be in a `enum`, and we avoid `static const`
// to avoid allocating storage for the constant.
const shape_id_t rb_invalid_shape_id = INVALID_SHAPE_ID;

unsigned int
rb_iseq_encoded_size(const rb_iseq_t *iseq)
{
Expand Down Expand Up @@ -157,6 +165,21 @@ rb_get_def_original_id(const rb_method_definition_t *def)
return def->original_id;
}

VALUE
rb_get_def_bmethod_proc(rb_method_definition_t *def)
{
RUBY_ASSERT(def->type == VM_METHOD_TYPE_BMETHOD);
return def->body.bmethod.proc;
}

rb_proc_t *
rb_jit_get_proc_ptr(VALUE procv)
{
rb_proc_t *proc;
GetProcPtr(procv, proc);
return proc;
}

int
rb_get_mct_argc(const rb_method_cfunc_t *mct)
{
Expand Down
11 changes: 11 additions & 0 deletions namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "ruby/internal/globals.h"
#include "ruby/util.h"
#include "vm_core.h"
#include "darray.h"

#include <stdio.h>

Expand Down Expand Up @@ -207,6 +208,15 @@ free_loading_table_entry(st_data_t key, st_data_t value, st_data_t arg)
return ST_DELETE;
}

static int
free_loaded_feature_index_i(st_data_t key, st_data_t value, st_data_t arg)
{
if (!FIXNUM_P(value)) {
rb_darray_free((void *)value);
}
return ST_CONTINUE;
}

static void
namespace_root_free(void *ptr)
{
Expand All @@ -218,6 +228,7 @@ namespace_root_free(void *ptr)
}

if (ns->loaded_features_index) {
st_foreach(ns->loaded_features_index, free_loaded_feature_index_i, 0);
st_free_table(ns->loaded_features_index);
}
}
Expand Down
6 changes: 3 additions & 3 deletions shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ enum shape_id_fl_type {
#undef RBIMPL_SHAPE_ID_FL
};

// This masks allows to check if a shape_id contains any ivar.
// It rely on ROOT_SHAPE_WITH_OBJ_ID==1.
enum {
// This mask allows to check if a shape_id contains any ivar.
// It relies on ROOT_SHAPE_WITH_OBJ_ID==1.
enum shape_id_mask {
SHAPE_ID_HAS_IVAR_MASK = SHAPE_ID_FL_TOO_COMPLEX | (SHAPE_ID_OFFSET_MASK - 1),
};

Expand Down
Loading