farce 0.1.0-arm-linux-gnu → 0.2.0-arm-linux-gnu
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +80 -1
- data/README.md +72 -16
- data/docs/gems/dry-types.md +8 -8
- data/docs/modes.md +67 -10
- data/ext/farce/atom.c +37 -22
- data/ext/farce/bounded_map.c +17 -13
- data/ext/farce/containers.h +15 -0
- data/ext/farce/counter.c +13 -18
- data/ext/farce/exchanger.c +5 -1
- data/ext/farce/farce.c +1 -1
- data/ext/farce/flag.c +39 -3
- data/ext/farce/io.c +3 -3
- data/ext/farce/lock.c +17 -23
- data/ext/farce/map.c +88 -66
- data/ext/farce/priority_queue.c +55 -43
- data/ext/farce/queue.c +10 -4
- data/ext/farce/reactor.c +52 -25
- data/ext/farce/reactor.h +1 -1
- data/ext/farce/signal.c +5 -1
- data/ext/farce/transaction.c +20 -24
- data/ext/farce/tree_map.c +33 -18
- data/ext/farce/trie.c +81 -43
- data/ext/farce/unshareable.c +168 -19
- data/ext/farce/unshared_io_pool.h +21 -12
- data/ext/farce/unshared_signal.c +13 -2
- data/ext/farce/unshared_wait.h +3 -0
- data/ext/farce/vector.c +82 -18
- data/ext/farce/weak_map.c +75 -63
- data/lib/farce/_yard/macros.rb +18 -3
- data/lib/farce/abstract/flag.rb +73 -0
- data/lib/farce/abstract/queue.rb +4 -3
- data/lib/farce/abstract/scheduler.rb +3 -3
- data/lib/farce/abstract/set.rb +17 -5
- data/lib/farce/abstract/sorted_set.rb +2 -2
- data/lib/farce/abstract/timer_queue.rb +49 -10
- data/lib/farce/abstract/vector.rb +510 -28
- data/lib/farce/atom.rb +1 -1
- data/lib/farce/class_mirror.rb +20 -7
- data/lib/farce/config.rb +7 -1
- data/lib/farce/engine/jvm/flag.rb +15 -3
- data/lib/farce/engine/ruby/3.4/farce.so +0 -0
- data/lib/farce/engine/ruby/4.0/farce.so +0 -0
- data/lib/farce/engine/ruby/shared/require_hook.rb +18 -0
- data/lib/farce/engine/ruby.rb +7 -0
- data/lib/farce/engine/shared/unshared_vector.rb +31 -4
- data/lib/farce/engine/shared/vector.rb +8 -0
- data/lib/farce/engine/shared/weak_map/index.rb +14 -1
- data/lib/farce/engine/truffleruby/native/flag.rb +15 -3
- data/lib/farce/envelope.rb +54 -7
- data/lib/farce/exchanger.rb +1 -1
- data/lib/farce/flag.rb +2 -0
- data/lib/farce/integrations/active_support.rb +1 -1
- data/lib/farce/integrations/bson.rb +1 -1
- data/lib/farce/integrations/cbor.rb +1 -1
- data/lib/farce/integrations/concurrent.rb +3 -3
- data/lib/farce/integrations/date.rb +8 -0
- data/lib/farce/integrations/dry_types.rb +7 -4
- data/lib/farce/integrations/json.rb +2 -2
- data/lib/farce/integrations/msgpack.rb +1 -1
- data/lib/farce/integrations/oj.rb +3 -4
- data/lib/farce/integrations/psych.rb +1 -1
- data/lib/farce/integrations/ractor_sharing.rb +1 -1
- data/lib/farce/integrations/sorted_set.rb +1 -1
- data/lib/farce/integrations/weakref.rb +9 -1
- data/lib/farce/integrations/yajl.rb +3 -3
- data/lib/farce/integrations.rb +33 -23
- data/lib/farce/internal/flag_waiting.rb +30 -0
- data/lib/farce/internal/freeze.rb +8 -3
- data/lib/farce/internal/map_value_modes.rb +1 -1
- data/lib/farce/internal/scheduler_lifecycle.rb +1 -1
- data/lib/farce/lazy.rb +4 -4
- data/lib/farce/lazy_ref.rb +3 -3
- data/lib/farce/lfu_map.rb +1 -1
- data/lib/farce/local/flag.rb +4 -0
- data/lib/farce/local/scoped.rb +1 -1
- data/lib/farce/lru_map.rb +1 -1
- data/lib/farce/map.rb +2 -2
- data/lib/farce/mode_manager/smart_rule.rb +138 -0
- data/lib/farce/mode_manager.rb +12 -3
- data/lib/farce/molecule.rb +2 -2
- data/lib/farce/pool.rb +1 -1
- data/lib/farce/port.rb +4 -4
- data/lib/farce/priority_queue.rb +1 -1
- data/lib/farce/proxy/register.rb +6 -0
- data/lib/farce/proxy/supervisor.rb +1 -1
- data/lib/farce/proxy.rb +7 -2
- data/lib/farce/queue.rb +1 -1
- data/lib/farce/scheduler.rb +2 -2
- data/lib/farce/set.rb +1 -1
- data/lib/farce/sorted_set.rb +1 -1
- data/lib/farce/timer_queue.rb +20 -6
- data/lib/farce/transaction/vector.rb +43 -9
- data/lib/farce/transaction/wrapper.rb +14 -0
- data/lib/farce/tree_map.rb +1 -1
- data/lib/farce/unsafe/lfu_map.rb +2 -0
- data/lib/farce/unsafe/lru_map.rb +2 -0
- data/lib/farce/unsafe/tree_map.rb +2 -0
- data/lib/farce/unshareable.rb +8 -19
- data/lib/farce/unshared/atom.rb +3 -0
- data/lib/farce/unshared/lfu_map.rb +2 -0
- data/lib/farce/unshared/lru_map.rb +2 -0
- data/lib/farce/unshared/map.rb +3 -0
- data/lib/farce/unshared/set.rb +1 -0
- data/lib/farce/unshared/sorted_set.rb +1 -0
- data/lib/farce/unshared/tree_map.rb +5 -1
- data/lib/farce/unshared/vector.rb +3 -0
- data/lib/farce/unshared/weak_atom.rb +5 -1
- data/lib/farce/unshared/weak_key_map.rb +3 -0
- data/lib/farce/unshared/weak_map.rb +3 -0
- data/lib/farce/unshared/weak_set.rb +1 -0
- data/lib/farce/unshared/weak_value_map.rb +3 -0
- data/lib/farce/vector.rb +44 -19
- data/lib/farce/version.rb +1 -1
- data/lib/farce.rb +11 -8
- metadata +5 -1
data/ext/farce/transaction.c
CHANGED
|
@@ -4,36 +4,29 @@
|
|
|
4
4
|
|
|
5
5
|
static VALUE cTransactionEntry;
|
|
6
6
|
|
|
7
|
-
static void
|
|
8
|
-
transaction_entry_mark(void *pointer)
|
|
9
|
-
{
|
|
10
|
-
farce_transaction_entry_t *entry = pointer;
|
|
11
|
-
rb_gc_mark_movable(entry->source);
|
|
12
|
-
rb_gc_mark_movable(entry->working);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
static void
|
|
16
|
-
transaction_entry_compact(void *pointer)
|
|
17
|
-
{
|
|
18
|
-
farce_transaction_entry_t *entry = pointer;
|
|
19
|
-
entry->source = rb_gc_location(entry->source);
|
|
20
|
-
entry->working = rb_gc_location(entry->working);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
7
|
static size_t
|
|
24
8
|
transaction_entry_memsize(const void *pointer)
|
|
25
9
|
{
|
|
26
10
|
return pointer ? sizeof(farce_transaction_entry_t) : 0;
|
|
27
11
|
}
|
|
28
12
|
|
|
13
|
+
RUBY_REFERENCES(transaction_entry_references) = {
|
|
14
|
+
RUBY_REF_EDGE(farce_transaction_entry_t, source),
|
|
15
|
+
RUBY_REF_EDGE(farce_transaction_entry_t, working),
|
|
16
|
+
RUBY_REF_END,
|
|
17
|
+
};
|
|
18
|
+
|
|
29
19
|
static const rb_data_type_t transaction_entry_type = {
|
|
30
20
|
.wrap_struct_name = "Farce::Internal::NativeTransactionEntry",
|
|
31
21
|
.function = {
|
|
32
|
-
.dmark =
|
|
22
|
+
.dmark = RUBY_REFS_LIST_PTR(transaction_entry_references),
|
|
33
23
|
.dfree = RUBY_TYPED_DEFAULT_FREE,
|
|
34
24
|
.dsize = transaction_entry_memsize,
|
|
35
|
-
.dcompact = transaction_entry_compact,
|
|
36
25
|
},
|
|
26
|
+
.flags =
|
|
27
|
+
RUBY_TYPED_DECL_MARKING |
|
|
28
|
+
RUBY_TYPED_FREE_IMMEDIATELY |
|
|
29
|
+
FARCE_TYPED_THREAD_SAFE_FREE,
|
|
37
30
|
};
|
|
38
31
|
|
|
39
32
|
VALUE
|
|
@@ -51,6 +44,9 @@ farce_transaction_entry_new(
|
|
|
51
44
|
.source_data = source_data, .working_data = working_data,
|
|
52
45
|
.lock = lock, .ops = ops,
|
|
53
46
|
};
|
|
47
|
+
/* Attempt-local copies are rescanned by every GC. They do not need the
|
|
48
|
+
* barriers or ownership scans used by long-lived containers. */
|
|
49
|
+
if (!NIL_P(working)) RB_OBJ_WB_UNPROTECT(working);
|
|
54
50
|
return object;
|
|
55
51
|
}
|
|
56
52
|
|
|
@@ -91,13 +87,13 @@ transaction_commit(VALUE namespace, VALUE entries, VALUE guards)
|
|
|
91
87
|
Check_Type(guards, T_ARRAY);
|
|
92
88
|
/* Type-check guards before acquiring participant locks. */
|
|
93
89
|
for (long i = 0; i < RARRAY_LEN(guards); i++) {
|
|
94
|
-
if (farce_transaction_flag_set(
|
|
90
|
+
if (farce_transaction_flag_set(rb_ary_entry(guards, i))) return Qfalse;
|
|
95
91
|
}
|
|
96
92
|
long count = RARRAY_LEN(entries);
|
|
97
93
|
VALUE buffer = 0;
|
|
98
94
|
farce_transaction_entry_t **ordered = ALLOCV_N(farce_transaction_entry_t *, buffer, count);
|
|
99
95
|
for (long i = 0; i < count; i++) {
|
|
100
|
-
ordered[i] = get_transaction_entry(
|
|
96
|
+
ordered[i] = get_transaction_entry(rb_ary_entry(entries, i));
|
|
101
97
|
}
|
|
102
98
|
qsort(ordered, (size_t)count, sizeof(*ordered), transaction_entry_order);
|
|
103
99
|
for (long i = 1; i < count; i++) {
|
|
@@ -128,7 +124,7 @@ transaction_commit(VALUE namespace, VALUE entries, VALUE guards)
|
|
|
128
124
|
}
|
|
129
125
|
if (valid) {
|
|
130
126
|
for (long i = 0; i < RARRAY_LEN(guards); i++) {
|
|
131
|
-
if (farce_transaction_flag_set(
|
|
127
|
+
if (farce_transaction_flag_set(rb_ary_entry(guards, i))) {
|
|
132
128
|
valid = false;
|
|
133
129
|
break;
|
|
134
130
|
}
|
|
@@ -233,7 +229,7 @@ transaction_reservation_body(VALUE opaque)
|
|
|
233
229
|
}
|
|
234
230
|
if (valid) {
|
|
235
231
|
for (long i = 0; i < RARRAY_LEN(reservation->guards); i++) {
|
|
236
|
-
if (farce_transaction_flag_set(
|
|
232
|
+
if (farce_transaction_flag_set(rb_ary_entry(reservation->guards, i))) {
|
|
237
233
|
valid = false;
|
|
238
234
|
break;
|
|
239
235
|
}
|
|
@@ -308,13 +304,13 @@ transaction_reserve(VALUE namespace, VALUE entries, VALUE guards, VALUE context)
|
|
|
308
304
|
Check_Type(entries, T_ARRAY);
|
|
309
305
|
Check_Type(guards, T_ARRAY);
|
|
310
306
|
for (long i = 0; i < RARRAY_LEN(guards); i++) {
|
|
311
|
-
(void)farce_transaction_flag_set(
|
|
307
|
+
(void)farce_transaction_flag_set(rb_ary_entry(guards, i));
|
|
312
308
|
}
|
|
313
309
|
long count = RARRAY_LEN(entries);
|
|
314
310
|
VALUE buffer = 0;
|
|
315
311
|
farce_transaction_entry_t **ordered = ALLOCV_N(farce_transaction_entry_t *, buffer, count);
|
|
316
312
|
for (long i = 0; i < count; i++) {
|
|
317
|
-
ordered[i] = get_transaction_entry(
|
|
313
|
+
ordered[i] = get_transaction_entry(rb_ary_entry(entries, i));
|
|
318
314
|
if (!ordered[i]->ops->reserve || !ordered[i]->ops->release) {
|
|
319
315
|
ALLOCV_END(buffer);
|
|
320
316
|
rb_raise(rb_eTypeError, "participant does not support commit reservations");
|
data/ext/farce/tree_map.c
CHANGED
|
@@ -471,8 +471,8 @@ tc_map_compact_node(tc_link *link)
|
|
|
471
471
|
|
|
472
472
|
if (link == NULL) return;
|
|
473
473
|
node = TC_MAP_NODE(link);
|
|
474
|
-
|
|
475
|
-
|
|
474
|
+
containers_gc_update(&node->key);
|
|
475
|
+
containers_gc_update(&node->value);
|
|
476
476
|
tc_map_compact_node(link->left);
|
|
477
477
|
tc_map_compact_node(link->right);
|
|
478
478
|
}
|
|
@@ -605,12 +605,10 @@ tc_core_map_compact(void *opaque)
|
|
|
605
605
|
tc_core_map *core = opaque;
|
|
606
606
|
if (core == NULL) return;
|
|
607
607
|
tc_map_compact_node(core->map.root);
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
core->publication_owner_fiber
|
|
611
|
-
|
|
612
|
-
core->publication_owner_ruby_thread =
|
|
613
|
-
rb_gc_location(core->publication_owner_ruby_thread);
|
|
608
|
+
containers_gc_update(&core->owner_fiber);
|
|
609
|
+
containers_gc_update(&core->owner_ruby_thread);
|
|
610
|
+
containers_gc_update(&core->publication_owner_fiber);
|
|
611
|
+
containers_gc_update(&core->publication_owner_ruby_thread);
|
|
614
612
|
}
|
|
615
613
|
|
|
616
614
|
static void
|
|
@@ -642,7 +640,7 @@ static const rb_data_type_t tc_unsafe_map_type = {
|
|
|
642
640
|
.dsize = tc_core_map_memsize,
|
|
643
641
|
.dcompact = tc_core_map_compact,
|
|
644
642
|
},
|
|
645
|
-
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
|
643
|
+
.flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | FARCE_TYPED_THREAD_SAFE_FREE,
|
|
646
644
|
};
|
|
647
645
|
|
|
648
646
|
static const rb_data_type_t tc_map_type = {
|
|
@@ -653,7 +651,7 @@ static const rb_data_type_t tc_map_type = {
|
|
|
653
651
|
.dsize = tc_core_map_memsize,
|
|
654
652
|
.dcompact = tc_core_map_compact,
|
|
655
653
|
},
|
|
656
|
-
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
|
654
|
+
.flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | FARCE_TYPED_THREAD_SAFE_FREE,
|
|
657
655
|
};
|
|
658
656
|
|
|
659
657
|
static const rb_data_type_t tc_shared_map_type = {
|
|
@@ -664,7 +662,11 @@ static const rb_data_type_t tc_shared_map_type = {
|
|
|
664
662
|
.dsize = tc_core_map_memsize,
|
|
665
663
|
.dcompact = tc_core_map_compact,
|
|
666
664
|
},
|
|
667
|
-
.flags =
|
|
665
|
+
.flags =
|
|
666
|
+
RUBY_TYPED_WB_PROTECTED |
|
|
667
|
+
RUBY_TYPED_FROZEN_SHAREABLE |
|
|
668
|
+
RUBY_TYPED_FREE_IMMEDIATELY |
|
|
669
|
+
FARCE_TYPED_THREAD_SAFE_FREE,
|
|
668
670
|
};
|
|
669
671
|
|
|
670
672
|
static VALUE
|
|
@@ -925,8 +927,8 @@ tc_core_map_lock(VALUE self, tc_core_map *core)
|
|
|
925
927
|
rb_raise(rb_eThreadError, "deadlock; recursive tree map access");
|
|
926
928
|
}
|
|
927
929
|
if (NIL_P(core->owner_fiber) && !publication_busy) {
|
|
928
|
-
core->owner_fiber
|
|
929
|
-
core->owner_ruby_thread
|
|
930
|
+
RB_OBJ_WRITE(self, &core->owner_fiber, current);
|
|
931
|
+
RB_OBJ_WRITE(self, &core->owner_ruby_thread, current_thread);
|
|
930
932
|
pthread_mutex_unlock(&core->lock);
|
|
931
933
|
return;
|
|
932
934
|
}
|
|
@@ -1731,8 +1733,8 @@ tc_core_map_each(VALUE self)
|
|
|
1731
1733
|
entry_count = RARRAY_LEN(entries);
|
|
1732
1734
|
for (index = 0; index < entry_count; index += 2) {
|
|
1733
1735
|
rb_yield(rb_assoc_new(
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
+
rb_ary_entry(entries, index),
|
|
1737
|
+
rb_ary_entry(entries, index + 1)
|
|
1736
1738
|
));
|
|
1737
1739
|
}
|
|
1738
1740
|
RB_GC_GUARD(entries);
|
|
@@ -1787,6 +1789,18 @@ tc_transaction_valid(farce_transaction_entry_t *entry)
|
|
|
1787
1789
|
source->map.revision == entry->version;
|
|
1788
1790
|
}
|
|
1789
1791
|
|
|
1792
|
+
/* A transaction transfers the tree's reference edges to a different owner. */
|
|
1793
|
+
static void
|
|
1794
|
+
tc_map_written_node(VALUE self, tc_link *link)
|
|
1795
|
+
{
|
|
1796
|
+
if (!link) return;
|
|
1797
|
+
tc_map_node *node = (tc_map_node *)link;
|
|
1798
|
+
RB_OBJ_WRITTEN(self, Qundef, node->key);
|
|
1799
|
+
RB_OBJ_WRITTEN(self, Qundef, node->value);
|
|
1800
|
+
tc_map_written_node(self, link->left);
|
|
1801
|
+
tc_map_written_node(self, link->right);
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1790
1804
|
static void
|
|
1791
1805
|
tc_transaction_apply(farce_transaction_entry_t *entry)
|
|
1792
1806
|
{
|
|
@@ -1800,6 +1814,7 @@ tc_transaction_apply(farce_transaction_entry_t *entry)
|
|
|
1800
1814
|
working->map.root = root;
|
|
1801
1815
|
working->map.size = size;
|
|
1802
1816
|
working->map.revision++;
|
|
1817
|
+
tc_map_written_node(entry->source, source->map.root);
|
|
1803
1818
|
}
|
|
1804
1819
|
|
|
1805
1820
|
static void
|
|
@@ -1813,8 +1828,8 @@ tc_transaction_reserve(farce_transaction_entry_t *entry, VALUE fiber, VALUE thre
|
|
|
1813
1828
|
{
|
|
1814
1829
|
tc_core_map *core = entry->source_data;
|
|
1815
1830
|
core->transaction_reserved = true;
|
|
1816
|
-
core->owner_fiber
|
|
1817
|
-
core->owner_ruby_thread
|
|
1831
|
+
RB_OBJ_WRITE(entry->source, &core->owner_fiber, fiber);
|
|
1832
|
+
RB_OBJ_WRITE(entry->source, &core->owner_ruby_thread, thread);
|
|
1818
1833
|
}
|
|
1819
1834
|
|
|
1820
1835
|
static void
|
|
@@ -1882,7 +1897,7 @@ tc_transaction_snapshot(VALUE self)
|
|
|
1882
1897
|
};
|
|
1883
1898
|
VALUE pairs = tc_core_map_call_locked(self, source, tc_transaction_snapshot_body, &snapshot);
|
|
1884
1899
|
for (long i = 0; i < RARRAY_LEN(pairs); i += 2) {
|
|
1885
|
-
tc_core_map_store(working,
|
|
1900
|
+
tc_core_map_store(working, rb_ary_entry(pairs, i), rb_ary_entry(pairs, i + 1));
|
|
1886
1901
|
}
|
|
1887
1902
|
RB_GC_GUARD(pairs);
|
|
1888
1903
|
return result;
|
data/ext/farce/trie.c
CHANGED
|
@@ -120,7 +120,7 @@ typedef struct {
|
|
|
120
120
|
trie_event_kind_t kind;
|
|
121
121
|
long begin;
|
|
122
122
|
long end;
|
|
123
|
-
VALUE name;
|
|
123
|
+
const VALUE *name;
|
|
124
124
|
long match_index;
|
|
125
125
|
} trie_capture_event_t;
|
|
126
126
|
|
|
@@ -180,6 +180,7 @@ typedef struct {
|
|
|
180
180
|
} trie_search_t;
|
|
181
181
|
|
|
182
182
|
typedef struct {
|
|
183
|
+
VALUE self;
|
|
183
184
|
const unsigned char *bytes;
|
|
184
185
|
size_t length;
|
|
185
186
|
size_t position;
|
|
@@ -213,8 +214,8 @@ trie_check_interrupts(void)
|
|
|
213
214
|
#ifdef FARCE_TRIE_FAILURE_INJECTION
|
|
214
215
|
if (!NIL_P(trie_interrupt_queue)) {
|
|
215
216
|
VALUE queues = trie_interrupt_queue;
|
|
216
|
-
VALUE ready =
|
|
217
|
-
VALUE release =
|
|
217
|
+
VALUE ready = rb_ary_entry(queues, 0);
|
|
218
|
+
VALUE release = rb_ary_entry(queues, 1);
|
|
218
219
|
trie_interrupt_queue = Qnil;
|
|
219
220
|
rb_funcall(ready, rb_intern("<<"), 1, Qtrue);
|
|
220
221
|
rb_funcall(release, rb_intern("pop"), 0);
|
|
@@ -277,7 +278,7 @@ static const rb_data_type_t trie_scratch_type = {
|
|
|
277
278
|
},
|
|
278
279
|
.parent = NULL,
|
|
279
280
|
.data = NULL,
|
|
280
|
-
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
|
281
|
+
.flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | FARCE_TYPED_THREAD_SAFE_FREE,
|
|
281
282
|
};
|
|
282
283
|
|
|
283
284
|
static void *
|
|
@@ -350,20 +351,20 @@ trie_mark(void *pointer)
|
|
|
350
351
|
size_t program_index;
|
|
351
352
|
if (!trie) return;
|
|
352
353
|
if (!NIL_P(trie->owner)) {
|
|
353
|
-
|
|
354
|
+
rb_gc_mark_movable(trie->owner);
|
|
354
355
|
return;
|
|
355
356
|
}
|
|
356
|
-
|
|
357
|
+
rb_gc_mark_movable(trie->tokens);
|
|
357
358
|
for (node_index = 0; node_index < trie->node_count; node_index++) {
|
|
358
359
|
trie_node_t *node = trie->nodes[node_index];
|
|
359
360
|
size_t index;
|
|
360
361
|
for (index = 0; index < node->static_count; index++) {
|
|
361
|
-
|
|
362
|
+
rb_gc_mark_movable(node->static_edges[index].label);
|
|
362
363
|
}
|
|
363
364
|
for (index = 0; index < node->regexp_count; index++) {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
365
|
+
rb_gc_mark_movable(node->regexp_edges[index].source);
|
|
366
|
+
rb_gc_mark_movable(node->regexp_edges[index].anchored);
|
|
367
|
+
rb_gc_mark_movable(node->regexp_edges[index].timeout);
|
|
367
368
|
}
|
|
368
369
|
}
|
|
369
370
|
for (program_index = 0; program_index < trie->program_count; program_index++) {
|
|
@@ -371,7 +372,38 @@ trie_mark(void *pointer)
|
|
|
371
372
|
size_t index;
|
|
372
373
|
for (index = 0; index < program->instruction_count; index++) {
|
|
373
374
|
if (program->instructions[index].opcode != TRIE_LITERAL_ALTERNATIVES) {
|
|
374
|
-
|
|
375
|
+
rb_gc_mark_movable(program->instructions[index].name);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
static void
|
|
382
|
+
trie_compact(void *pointer)
|
|
383
|
+
{
|
|
384
|
+
trie_t *trie = pointer;
|
|
385
|
+
if (!trie) return;
|
|
386
|
+
if (!NIL_P(trie->owner)) {
|
|
387
|
+
containers_gc_update(&trie->owner);
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
containers_gc_update(&trie->tokens);
|
|
391
|
+
for (size_t n = 0; n < trie->node_count; n++) {
|
|
392
|
+
trie_node_t *node = trie->nodes[n];
|
|
393
|
+
for (size_t i = 0; i < node->static_count; i++) {
|
|
394
|
+
containers_gc_update(&node->static_edges[i].label);
|
|
395
|
+
}
|
|
396
|
+
for (size_t i = 0; i < node->regexp_count; i++) {
|
|
397
|
+
containers_gc_update(&node->regexp_edges[i].source);
|
|
398
|
+
containers_gc_update(&node->regexp_edges[i].anchored);
|
|
399
|
+
containers_gc_update(&node->regexp_edges[i].timeout);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
for (size_t p = 0; p < trie->program_count; p++) {
|
|
403
|
+
trie_program_t *program = trie->programs[p];
|
|
404
|
+
for (size_t i = 0; i < program->instruction_count; i++) {
|
|
405
|
+
if (program->instructions[i].opcode != TRIE_LITERAL_ALTERNATIVES) {
|
|
406
|
+
containers_gc_update(&program->instructions[i].name);
|
|
375
407
|
}
|
|
376
408
|
}
|
|
377
409
|
}
|
|
@@ -478,10 +510,15 @@ static const rb_data_type_t trie_type = {
|
|
|
478
510
|
.wrap_struct_name = "Farce::Internal::Trie",
|
|
479
511
|
.function = {
|
|
480
512
|
.dmark = trie_mark,
|
|
513
|
+
.dcompact = trie_compact,
|
|
481
514
|
.dfree = trie_free,
|
|
482
515
|
.dsize = trie_memsize,
|
|
483
516
|
},
|
|
484
|
-
.flags =
|
|
517
|
+
.flags =
|
|
518
|
+
RUBY_TYPED_WB_PROTECTED |
|
|
519
|
+
RUBY_TYPED_FREE_IMMEDIATELY |
|
|
520
|
+
RUBY_TYPED_FROZEN_SHAREABLE |
|
|
521
|
+
FARCE_TYPED_THREAD_SAFE_FREE,
|
|
485
522
|
};
|
|
486
523
|
|
|
487
524
|
static VALUE
|
|
@@ -846,8 +883,8 @@ trie_parse_capture(trie_parser_t *parser)
|
|
|
846
883
|
instruction.name = Qnil;
|
|
847
884
|
if (!trie_program_add_instruction(parser->program, instruction)) return false;
|
|
848
885
|
name = rb_enc_str_new((const char *)parser->bytes + name_start, (long)name_length, rb_usascii_encoding());
|
|
849
|
-
|
|
850
|
-
parser->program->instructions[parser->program->instruction_count - 1].name
|
|
886
|
+
name = rb_str_to_interned_str(name);
|
|
887
|
+
RB_OBJ_WRITE(parser->self, &parser->program->instructions[parser->program->instruction_count - 1].name, name);
|
|
851
888
|
parser->program->capture_count++;
|
|
852
889
|
if (opcode == TRIE_CAPTURE_DIGIT || opcode == TRIE_CAPTURE_WORD) {
|
|
853
890
|
parser->program->requires_ascii_input = true;
|
|
@@ -1028,7 +1065,7 @@ trie_program_cache_rebuild(trie_t *trie, size_t capacity)
|
|
|
1028
1065
|
}
|
|
1029
1066
|
|
|
1030
1067
|
static trie_program_t *
|
|
1031
|
-
trie_compile_program(trie_t *trie, VALUE source, int options, VALUE timeout)
|
|
1068
|
+
trie_compile_program(VALUE self, trie_t *trie, VALUE source, int options, VALUE timeout)
|
|
1032
1069
|
{
|
|
1033
1070
|
size_t length;
|
|
1034
1071
|
int encoding;
|
|
@@ -1068,6 +1105,7 @@ trie_compile_program(trie_t *trie, VALUE source, int options, VALUE timeout)
|
|
|
1068
1105
|
program->key_options = options;
|
|
1069
1106
|
|
|
1070
1107
|
memset(&parser, 0, sizeof(parser));
|
|
1108
|
+
parser.self = self;
|
|
1071
1109
|
parser.bytes = program->key;
|
|
1072
1110
|
parser.length = length;
|
|
1073
1111
|
parser.program = program;
|
|
@@ -1199,7 +1237,7 @@ trie_regexp_edge_equal(const trie_regexp_edge_t *edge, VALUE source,
|
|
|
1199
1237
|
}
|
|
1200
1238
|
|
|
1201
1239
|
static trie_node_t *
|
|
1202
|
-
trie_insert_string(trie_t *trie, trie_node_t *node, VALUE string)
|
|
1240
|
+
trie_insert_string(VALUE self, trie_t *trie, trie_node_t *node, VALUE string)
|
|
1203
1241
|
{
|
|
1204
1242
|
size_t offset = 0;
|
|
1205
1243
|
size_t length = (size_t)RSTRING_LEN(string);
|
|
@@ -1210,7 +1248,7 @@ trie_insert_string(trie_t *trie, trie_node_t *node, VALUE string)
|
|
|
1210
1248
|
VALUE label = trie_frozen_string(string, (long)offset, (long)(length - offset));
|
|
1211
1249
|
size_t edge_index = node->static_count;
|
|
1212
1250
|
trie_ensure_static_edges(node, node->static_count + 1);
|
|
1213
|
-
node->static_edges[edge_index].label
|
|
1251
|
+
RB_OBJ_WRITE(self, &node->static_edges[edge_index].label, label);
|
|
1214
1252
|
node->static_edges[edge_index].child = child;
|
|
1215
1253
|
node->static_edges[edge_index].encoding = rb_enc_get_index(label);
|
|
1216
1254
|
node->static_count++;
|
|
@@ -1233,13 +1271,13 @@ trie_insert_string(trie_t *trie, trie_node_t *node, VALUE string)
|
|
|
1233
1271
|
VALUE prefix = trie_frozen_string(old_label, 0, (long)shared);
|
|
1234
1272
|
VALUE old_suffix = trie_frozen_string(old_label, (long)shared, (long)(edge_length - shared));
|
|
1235
1273
|
trie_ensure_static_edges(middle, shared == length - offset ? 1 : 2);
|
|
1236
|
-
middle->static_edges[0].label
|
|
1274
|
+
RB_OBJ_WRITE(self, &middle->static_edges[0].label, old_suffix);
|
|
1237
1275
|
middle->static_edges[0].child = edge->child;
|
|
1238
1276
|
middle->static_edges[0].encoding = rb_enc_get_index(old_suffix);
|
|
1239
1277
|
middle->static_count = 1;
|
|
1240
1278
|
trie->static_edge_count++;
|
|
1241
1279
|
trie_index_static_edge(trie, middle, 0);
|
|
1242
|
-
edge->label
|
|
1280
|
+
RB_OBJ_WRITE(self, &edge->label, prefix);
|
|
1243
1281
|
edge->child = middle;
|
|
1244
1282
|
edge->encoding = rb_enc_get_index(prefix);
|
|
1245
1283
|
offset += shared;
|
|
@@ -1251,7 +1289,7 @@ trie_insert_string(trie_t *trie, trie_node_t *node, VALUE string)
|
|
|
1251
1289
|
}
|
|
1252
1290
|
trie_node_t *child = trie_node_new(trie);
|
|
1253
1291
|
VALUE new_suffix = trie_frozen_string(string, (long)offset, (long)(length - offset));
|
|
1254
|
-
middle->static_edges[1].label
|
|
1292
|
+
RB_OBJ_WRITE(self, &middle->static_edges[1].label, new_suffix);
|
|
1255
1293
|
middle->static_edges[1].child = child;
|
|
1256
1294
|
middle->static_edges[1].encoding = rb_enc_get_index(new_suffix);
|
|
1257
1295
|
middle->static_count = 2;
|
|
@@ -1267,7 +1305,7 @@ trie_insert_string(trie_t *trie, trie_node_t *node, VALUE string)
|
|
|
1267
1305
|
}
|
|
1268
1306
|
|
|
1269
1307
|
static trie_node_t *
|
|
1270
|
-
trie_insert_regexp(trie_t *trie, trie_node_t *node, VALUE regexp)
|
|
1308
|
+
trie_insert_regexp(VALUE self, trie_t *trie, trie_node_t *node, VALUE regexp)
|
|
1271
1309
|
{
|
|
1272
1310
|
VALUE source = RREGEXP_SRC(regexp);
|
|
1273
1311
|
VALUE source_copy = rb_str_dup(source);
|
|
@@ -1287,13 +1325,13 @@ trie_insert_regexp(trie_t *trie, trie_node_t *node, VALUE regexp)
|
|
|
1287
1325
|
}
|
|
1288
1326
|
}
|
|
1289
1327
|
VALUE anchored = trie_anchored_regexp(source_copy, options, timeout);
|
|
1290
|
-
trie_program_t *program = trie_compile_program(trie, source_copy, options, timeout);
|
|
1328
|
+
trie_program_t *program = trie_compile_program(self, trie, source_copy, options, timeout);
|
|
1291
1329
|
trie_node_t *child = trie_node_new(trie);
|
|
1292
1330
|
trie_ensure_regexp_edges(node, node->regexp_count + 1);
|
|
1293
1331
|
trie_regexp_edge_t *edge = &node->regexp_edges[node->regexp_count++];
|
|
1294
|
-
edge->source
|
|
1295
|
-
edge->anchored
|
|
1296
|
-
edge->timeout
|
|
1332
|
+
RB_OBJ_WRITE(self, &edge->source, source_copy);
|
|
1333
|
+
RB_OBJ_WRITE(self, &edge->anchored, anchored);
|
|
1334
|
+
RB_OBJ_WRITE(self, &edge->timeout, timeout);
|
|
1297
1335
|
edge->options = options;
|
|
1298
1336
|
edge->program = program;
|
|
1299
1337
|
edge->child = child;
|
|
@@ -1306,23 +1344,23 @@ trie_insert_regexp(trie_t *trie, trie_node_t *node, VALUE regexp)
|
|
|
1306
1344
|
}
|
|
1307
1345
|
|
|
1308
1346
|
static void
|
|
1309
|
-
trie_insert_entry(trie_t *trie, VALUE parts, uint32_t token)
|
|
1347
|
+
trie_insert_entry(VALUE self, trie_t *trie, VALUE parts, uint32_t token)
|
|
1310
1348
|
{
|
|
1311
1349
|
trie_node_t *node = trie->root;
|
|
1312
1350
|
long index;
|
|
1313
1351
|
Check_Type(parts, T_ARRAY);
|
|
1314
1352
|
for (index = 0; index < RARRAY_LEN(parts); index++) {
|
|
1315
|
-
VALUE part =
|
|
1353
|
+
VALUE part = rb_ary_entry(parts, index);
|
|
1316
1354
|
if (RB_TYPE_P(part, T_STRING)) {
|
|
1317
1355
|
VALUE stable_part = rb_str_new_frozen(part);
|
|
1318
1356
|
if (rb_enc_str_coderange(stable_part) == ENC_CODERANGE_BROKEN) {
|
|
1319
1357
|
rb_raise(rb_eArgError, "trie literal has invalid encoding");
|
|
1320
1358
|
}
|
|
1321
|
-
node = trie_insert_string(trie, node, stable_part);
|
|
1359
|
+
node = trie_insert_string(self, trie, node, stable_part);
|
|
1322
1360
|
RB_GC_GUARD(stable_part);
|
|
1323
1361
|
}
|
|
1324
1362
|
else if (rb_obj_is_kind_of(part, rb_cRegexp)) {
|
|
1325
|
-
node = trie_insert_regexp(trie, node, part);
|
|
1363
|
+
node = trie_insert_regexp(self, trie, node, part);
|
|
1326
1364
|
}
|
|
1327
1365
|
else {
|
|
1328
1366
|
rb_raise(rb_eTypeError, "trie parts must be strings or regular expressions");
|
|
@@ -1386,7 +1424,7 @@ trie_initialize(VALUE self, VALUE entries, VALUE tokens)
|
|
|
1386
1424
|
token_identities = rb_hash_new();
|
|
1387
1425
|
rb_funcall(token_identities, rb_intern("compare_by_identity"), 0);
|
|
1388
1426
|
for (index = 0; index < RARRAY_LEN(tokens); index++) {
|
|
1389
|
-
VALUE token =
|
|
1427
|
+
VALUE token = rb_ary_entry(tokens, index);
|
|
1390
1428
|
containers_check_shareable(token);
|
|
1391
1429
|
if (rb_hash_lookup2(token_identities, token, Qundef) != Qundef) {
|
|
1392
1430
|
rb_raise(rb_eArgError, "trie tokens must have unique identities");
|
|
@@ -1396,24 +1434,24 @@ trie_initialize(VALUE self, VALUE entries, VALUE tokens)
|
|
|
1396
1434
|
if ((index & (TRIE_INTERRUPT_INTERVAL - 1)) == TRIE_INTERRUPT_INTERVAL - 1) trie_check_interrupts();
|
|
1397
1435
|
}
|
|
1398
1436
|
rb_obj_freeze(token_copy);
|
|
1399
|
-
trie->tokens
|
|
1437
|
+
RB_OBJ_WRITE(self, &trie->tokens, token_copy);
|
|
1400
1438
|
trie->root = trie_node_new(trie);
|
|
1401
1439
|
|
|
1402
1440
|
for (index = 0; index < RARRAY_LEN(entries); index++) {
|
|
1403
|
-
VALUE entry =
|
|
1441
|
+
VALUE entry = rb_ary_entry(entries, index);
|
|
1404
1442
|
VALUE parts;
|
|
1405
1443
|
VALUE identifier;
|
|
1406
1444
|
unsigned long id;
|
|
1407
1445
|
Check_Type(entry, T_ARRAY);
|
|
1408
1446
|
if (RARRAY_LEN(entry) != 2) rb_raise(rb_eArgError, "trie entry must contain parts and token id");
|
|
1409
|
-
parts =
|
|
1410
|
-
identifier =
|
|
1447
|
+
parts = rb_ary_entry(entry, 0);
|
|
1448
|
+
identifier = rb_ary_entry(entry, 1);
|
|
1411
1449
|
if (!RB_INTEGER_TYPE_P(identifier)) rb_raise(rb_eTypeError, "trie token id must be an integer");
|
|
1412
1450
|
id = NUM2ULONG(identifier);
|
|
1413
1451
|
if (id >= (unsigned long)RARRAY_LEN(token_copy) || id > UINT32_MAX) {
|
|
1414
1452
|
rb_raise(rb_eArgError, "trie token id is out of range");
|
|
1415
1453
|
}
|
|
1416
|
-
trie_insert_entry(trie, parts, (uint32_t)id);
|
|
1454
|
+
trie_insert_entry(self, trie, parts, (uint32_t)id);
|
|
1417
1455
|
if ((index & (TRIE_INTERRUPT_INTERVAL - 1)) == TRIE_INTERRUPT_INTERVAL - 1) trie_check_interrupts();
|
|
1418
1456
|
}
|
|
1419
1457
|
trie->initialized = true;
|
|
@@ -1477,7 +1515,7 @@ trie_search_ensure_events(trie_search_t *search, size_t minimum)
|
|
|
1477
1515
|
}
|
|
1478
1516
|
|
|
1479
1517
|
static void
|
|
1480
|
-
trie_search_append_native(trie_search_t *search, long begin, long end, VALUE name)
|
|
1518
|
+
trie_search_append_native(trie_search_t *search, long begin, long end, const VALUE *name)
|
|
1481
1519
|
{
|
|
1482
1520
|
trie_capture_event_t *event;
|
|
1483
1521
|
trie_search_ensure_events(search, search->event_count + 1);
|
|
@@ -1500,7 +1538,7 @@ trie_search_append_ruby(trie_search_t *search, VALUE match)
|
|
|
1500
1538
|
event = &search->events[search->event_count++];
|
|
1501
1539
|
event->kind = TRIE_EVENT_RUBY;
|
|
1502
1540
|
event->begin = event->end = 0;
|
|
1503
|
-
event->name =
|
|
1541
|
+
event->name = NULL;
|
|
1504
1542
|
event->match_index = match_index;
|
|
1505
1543
|
}
|
|
1506
1544
|
|
|
@@ -1536,7 +1574,7 @@ trie_program_match(const trie_program_t *program, VALUE input, long cursor,
|
|
|
1536
1574
|
trie_search_work_checkpoint(search);
|
|
1537
1575
|
}
|
|
1538
1576
|
if (cursor == begin) return false;
|
|
1539
|
-
trie_search_append_native(search, begin, cursor, instruction->name);
|
|
1577
|
+
trie_search_append_native(search, begin, cursor, &instruction->name);
|
|
1540
1578
|
}
|
|
1541
1579
|
}
|
|
1542
1580
|
if (program->end_anchor && cursor != length) return false;
|
|
@@ -1633,17 +1671,17 @@ static void
|
|
|
1633
1671
|
trie_materialize_captures(trie_search_t *search, VALUE *captures, VALUE *named)
|
|
1634
1672
|
{
|
|
1635
1673
|
size_t index;
|
|
1636
|
-
*captures =
|
|
1674
|
+
*captures = rb_ary_new_capa((long)search->event_count);
|
|
1637
1675
|
*named = rb_hash_new();
|
|
1638
1676
|
for (index = 0; index < search->event_count; index++) {
|
|
1639
1677
|
trie_capture_event_t *event = &search->events[index];
|
|
1640
1678
|
if (event->kind == TRIE_EVENT_NATIVE) {
|
|
1641
1679
|
VALUE value = rb_str_subseq(search->input, event->begin, event->end - event->begin);
|
|
1642
1680
|
rb_ary_push(*captures, value);
|
|
1643
|
-
trie_merge_named(*named, event->name, value);
|
|
1681
|
+
trie_merge_named(*named, *event->name, value);
|
|
1644
1682
|
}
|
|
1645
1683
|
else {
|
|
1646
|
-
VALUE match =
|
|
1684
|
+
VALUE match = rb_ary_entry(search->matches, event->match_index);
|
|
1647
1685
|
VALUE edge_captures = rb_funcall(match, id_captures, 0);
|
|
1648
1686
|
VALUE edge_named = rb_funcall(match, id_named_captures, 0);
|
|
1649
1687
|
trie_named_merge_t merge = {.destination = *named};
|
|
@@ -1743,7 +1781,7 @@ trie_emit_terminal(trie_search_t *search, trie_frame_t *frame)
|
|
|
1743
1781
|
if (trie_seen(search, id)) continue;
|
|
1744
1782
|
trie_materialize_captures(search, &captures, &named);
|
|
1745
1783
|
suffix = rb_str_subseq(search->input, frame->cursor, search->input_length - frame->cursor);
|
|
1746
|
-
token =
|
|
1784
|
+
token = rb_ary_entry(search->trie->tokens, (long)id);
|
|
1747
1785
|
if (search->stream) {
|
|
1748
1786
|
rb_yield_values(4, token, captures, named, suffix);
|
|
1749
1787
|
continue;
|
|
@@ -1930,7 +1968,7 @@ trie_initialize_copy(VALUE self, VALUE other)
|
|
|
1930
1968
|
trie_release_contents(destination);
|
|
1931
1969
|
memset(destination, 0, sizeof(*destination));
|
|
1932
1970
|
destination->tokens = Qnil;
|
|
1933
|
-
destination->owner
|
|
1971
|
+
RB_OBJ_WRITE(self, &destination->owner, owner);
|
|
1934
1972
|
destination->initialized = true;
|
|
1935
1973
|
rb_obj_freeze(self);
|
|
1936
1974
|
containers_publish_native_with_references(self, trie_validate_references);
|