ytljit 0.0.8 → 0.0.9
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.
- data/ext/code_alloc.c +2 -2
- data/ext/memory.c +2 -5
- data/ext/thread.c +144 -0
- data/ext/thread.h +24 -0
- data/ext/ytljit.c +33 -6
- data/ext/ytljit.h +33 -0
- data/lib/ytljit.rb +1 -1
- data/lib/ytljit/asm.rb +11 -4
- data/lib/ytljit/asmext_x64.rb +1 -1
- data/lib/ytljit/asmext_x86.rb +1 -1
- data/lib/ytljit/dyna_method.rb +136 -0
- data/lib/ytljit/marshal.rb +11 -0
- data/lib/ytljit/type.rb +2 -2
- data/lib/ytljit/vm.rb +781 -211
- data/lib/ytljit/vm_codegen.rb +73 -24
- data/lib/ytljit/vm_cruby_obj.rb +42 -30
- data/lib/ytljit/vm_inline_method.rb +40 -14
- data/lib/ytljit/vm_sendnode.rb +609 -190
- data/lib/ytljit/vm_trans.rb +60 -16
- data/lib/ytljit/vm_type.rb +29 -9
- data/lib/ytljit/vm_type_gen.rb +131 -56
- data/test/foo.rb +12 -0
- metadata +9 -16
data/ext/code_alloc.c
CHANGED
@@ -175,11 +175,11 @@ search_free_chunk(CodeSpaceArena *arena)
|
|
175
175
|
while (arena) {
|
176
176
|
for (i = 0;(cbitmap = arena->bitmap[i]) == 0; i++);
|
177
177
|
if (i < alocarea_off) {
|
178
|
-
arena_search_tab[logsize] = arena;
|
179
|
-
|
180
178
|
/* found free chunk */
|
181
179
|
int bitpos = ffs64(cbitmap);
|
182
180
|
|
181
|
+
arena_search_tab[logsize] = arena;
|
182
|
+
|
183
183
|
/* bitmap free -> used */
|
184
184
|
// fprintf(stderr, "%x %x\n", bitpos, arena->bitmap[i]);
|
185
185
|
arena->bitmap[i] = cbitmap & (cbitmap - 1);
|
data/ext/memory.c
CHANGED
@@ -26,7 +26,7 @@ ytl_arena_mark(struct ArenaHeader *arenah)
|
|
26
26
|
start = arenah->lastptr;
|
27
27
|
appear = 1;
|
28
28
|
}
|
29
|
-
else if (appear)
|
29
|
+
else if (appear) {
|
30
30
|
start = bodyptr->body;
|
31
31
|
}
|
32
32
|
else {
|
@@ -47,8 +47,6 @@ ytl_arena_mark(struct ArenaHeader *arenah)
|
|
47
47
|
void
|
48
48
|
ytl_arena_free(struct ArenaHeader *arenah)
|
49
49
|
{
|
50
|
-
VALUE *base;
|
51
|
-
VALUE *start;
|
52
50
|
struct ArenaBody *curptr;
|
53
51
|
struct ArenaBody *curptr_next;
|
54
52
|
|
@@ -169,7 +167,6 @@ ytl_arena_emit(VALUE self, VALUE offset, VALUE src)
|
|
169
167
|
struct ArenaHeader *arenah;
|
170
168
|
|
171
169
|
int raw_offset;
|
172
|
-
int newsize;
|
173
170
|
VALUE *newlastptr;
|
174
171
|
|
175
172
|
Data_Get_Struct(self, struct ArenaHeader, arenah);
|
@@ -228,7 +225,7 @@ ytl_arena_to_s(VALUE self)
|
|
228
225
|
|
229
226
|
Data_Get_Struct(self, struct ArenaHeader, arenah);
|
230
227
|
|
231
|
-
return rb_sprintf("#<Arena %p size=%
|
228
|
+
return rb_sprintf("#<Arena %p size=%lu body=%p last=%p>",
|
232
229
|
(void *)self,
|
233
230
|
ytl_arena_size(self) / 2,
|
234
231
|
(void *)arenah->body->body,
|
data/ext/thread.c
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
#include <stdlib.h>
|
2
|
+
#include <pthread.h>
|
3
|
+
#include "ruby.h"
|
4
|
+
|
5
|
+
#include "ytljit.h"
|
6
|
+
#include "thread.h"
|
7
|
+
|
8
|
+
VALUE ytl_cThread;
|
9
|
+
|
10
|
+
static void
|
11
|
+
ytl_thread_mark(struct ytl_thread *th)
|
12
|
+
{
|
13
|
+
rb_gc_mark(th->pself);
|
14
|
+
rb_gc_mark(th->cself);
|
15
|
+
}
|
16
|
+
|
17
|
+
/* You may think arguments order is wrong. But it is correct.
|
18
|
+
This is for efficient code. See SendThreadNewNode#compile in
|
19
|
+
github#ytl/lib/ytl/thread.rb
|
20
|
+
*/
|
21
|
+
VALUE
|
22
|
+
ytl_thread_create(void *argv, void *(*entry)(void *))
|
23
|
+
{
|
24
|
+
struct ytl_thread *th;
|
25
|
+
|
26
|
+
th = malloc(sizeof(struct ytl_thread));
|
27
|
+
th->pself = ((VALUE *)argv)[4];
|
28
|
+
th->cself = ((VALUE *)argv)[3];
|
29
|
+
pthread_attr_init(&th->attr);
|
30
|
+
pthread_attr_setstacksize(&th->attr, 64 * 1024);
|
31
|
+
pthread_create(&th->thread, &th->attr, entry, argv);
|
32
|
+
|
33
|
+
//printf("%x %x \n", th->pself, th->cself);
|
34
|
+
|
35
|
+
return Data_Wrap_Struct(ytl_cThread, ytl_thread_mark, NULL, (void *)th);
|
36
|
+
}
|
37
|
+
|
38
|
+
static void
|
39
|
+
ytl_obj_copy(VALUE dest, VALUE obj)
|
40
|
+
{
|
41
|
+
rb_copy_generic_ivar(dest, obj);
|
42
|
+
rb_gc_copy_finalizer(dest, obj);
|
43
|
+
rb_copy_generic_ivar(dest, obj);
|
44
|
+
rb_gc_copy_finalizer(dest, obj);
|
45
|
+
switch (TYPE(obj)) {
|
46
|
+
case T_OBJECT:
|
47
|
+
if (!(RBASIC(dest)->flags & ROBJECT_EMBED) && ROBJECT_IVPTR(dest)) {
|
48
|
+
xfree(ROBJECT_IVPTR(dest));
|
49
|
+
ROBJECT(dest)->as.heap.ivptr = 0;
|
50
|
+
ROBJECT(dest)->as.heap.numiv = 0;
|
51
|
+
ROBJECT(dest)->as.heap.iv_index_tbl = 0;
|
52
|
+
}
|
53
|
+
if (RBASIC(obj)->flags & ROBJECT_EMBED) {
|
54
|
+
MEMCPY(ROBJECT(dest)->as.ary, ROBJECT(obj)->as.ary, VALUE, ROBJECT_EMBED_LEN_MAX);
|
55
|
+
RBASIC(dest)->flags |= ROBJECT_EMBED;
|
56
|
+
}
|
57
|
+
else {
|
58
|
+
long len = ROBJECT(obj)->as.heap.numiv;
|
59
|
+
VALUE *ptr = ALLOC_N(VALUE, len);
|
60
|
+
MEMCPY(ptr, ROBJECT(obj)->as.heap.ivptr, VALUE, len);
|
61
|
+
ROBJECT(dest)->as.heap.ivptr = ptr;
|
62
|
+
ROBJECT(dest)->as.heap.numiv = len;
|
63
|
+
ROBJECT(dest)->as.heap.iv_index_tbl = ROBJECT(obj)->as.heap.iv_index_tbl;
|
64
|
+
RBASIC(dest)->flags &= ~ROBJECT_EMBED;
|
65
|
+
}
|
66
|
+
break;
|
67
|
+
|
68
|
+
#if 0
|
69
|
+
case T_CLASS:
|
70
|
+
case T_MODULE:
|
71
|
+
if (RCLASS_IV_TBL(dest)) {
|
72
|
+
st_free_table(RCLASS_IV_TBL(dest));
|
73
|
+
RCLASS_IV_TBL(dest) = 0;
|
74
|
+
}
|
75
|
+
if (RCLASS_CONST_TBL(dest)) {
|
76
|
+
rb_free_const_table(RCLASS_CONST_TBL(dest));
|
77
|
+
RCLASS_CONST_TBL(dest) = 0;
|
78
|
+
}
|
79
|
+
if (RCLASS_IV_TBL(obj)) {
|
80
|
+
RCLASS_IV_TBL(dest) = st_copy(RCLASS_IV_TBL(obj));
|
81
|
+
}
|
82
|
+
break;
|
83
|
+
#endif
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
void
|
88
|
+
ytl_thread_exit(VALUE val)
|
89
|
+
{
|
90
|
+
pthread_exit((void *)val);
|
91
|
+
}
|
92
|
+
|
93
|
+
VALUE
|
94
|
+
ytl_thread_join(VALUE self)
|
95
|
+
{
|
96
|
+
struct ytl_thread *th;
|
97
|
+
|
98
|
+
Data_Get_Struct(self, struct ytl_thread, th);
|
99
|
+
pthread_join(th->thread, NULL);
|
100
|
+
pthread_attr_destroy(&th->attr);
|
101
|
+
|
102
|
+
return self;
|
103
|
+
}
|
104
|
+
|
105
|
+
VALUE
|
106
|
+
ytl_thread_merge(VALUE self, VALUE newself)
|
107
|
+
{
|
108
|
+
struct ytl_thread *th;
|
109
|
+
Data_Get_Struct(self, struct ytl_thread, th);
|
110
|
+
|
111
|
+
if (th->pself != newself) {
|
112
|
+
ytl_obj_copy(th->pself, newself);
|
113
|
+
}
|
114
|
+
|
115
|
+
return self;
|
116
|
+
}
|
117
|
+
|
118
|
+
VALUE
|
119
|
+
ytl_thread_pself(VALUE self)
|
120
|
+
{
|
121
|
+
struct ytl_thread *th;
|
122
|
+
|
123
|
+
Data_Get_Struct(self, struct ytl_thread, th);
|
124
|
+
return th->pself;
|
125
|
+
}
|
126
|
+
|
127
|
+
VALUE
|
128
|
+
ytl_thread_set_pself(VALUE self, VALUE val)
|
129
|
+
{
|
130
|
+
struct ytl_thread *th;
|
131
|
+
|
132
|
+
Data_Get_Struct(self, struct ytl_thread, th);
|
133
|
+
th->pself = val;
|
134
|
+
return val;
|
135
|
+
}
|
136
|
+
|
137
|
+
VALUE
|
138
|
+
ytl_thread_cself(VALUE self)
|
139
|
+
{
|
140
|
+
struct ytl_thread *th;
|
141
|
+
|
142
|
+
Data_Get_Struct(self, struct ytl_thread, th);
|
143
|
+
return th->cself;
|
144
|
+
}
|
data/ext/thread.h
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
enum ytl_thread_status {
|
2
|
+
YTL_RUN = 0,
|
3
|
+
YTL_SLEEP = 1,
|
4
|
+
YTL_ABORTING = 2,
|
5
|
+
YTL_DEAD = 3,
|
6
|
+
};
|
7
|
+
|
8
|
+
struct ytl_thread {
|
9
|
+
enum ytl_thread_status status;
|
10
|
+
pthread_t thread;
|
11
|
+
pthread_attr_t attr;
|
12
|
+
VALUE pself; /* thread creater's self */
|
13
|
+
VALUE cself; /* child thread's self */
|
14
|
+
};
|
15
|
+
|
16
|
+
extern VALUE ytl_thread_create(void *, void *(*)(void *));
|
17
|
+
extern void ytl_thread_exit(VALUE);
|
18
|
+
extern VALUE ytl_thread_join(VALUE);
|
19
|
+
extern VALUE ytl_thread_merge(VALUE, VALUE);
|
20
|
+
extern VALUE ytl_thread_pself(VALUE);
|
21
|
+
extern VALUE ytl_thread_set_pself(VALUE, VALUE);
|
22
|
+
extern VALUE ytl_thread_cself(VALUE);
|
23
|
+
extern VALUE ytl_cThread;
|
24
|
+
|
data/ext/ytljit.c
CHANGED
@@ -6,6 +6,7 @@
|
|
6
6
|
#include "ruby/st.h"
|
7
7
|
|
8
8
|
#include "ytljit.h"
|
9
|
+
#include "thread.h"
|
9
10
|
|
10
11
|
VALUE ytl_mYTLJit;
|
11
12
|
VALUE ytl_cCodeSpace;
|
@@ -106,7 +107,6 @@ ytl_method_address_of_raw(VALUE klass, VALUE mname)
|
|
106
107
|
VALUE
|
107
108
|
ytl_binding_to_a(VALUE self)
|
108
109
|
{
|
109
|
-
rb_proc_t *proc;
|
110
110
|
rb_binding_t *bptr;
|
111
111
|
rb_env_t *env;
|
112
112
|
VALUE resary;
|
@@ -337,9 +337,23 @@ ytl_code_call(int argc, VALUE *argv, VALUE self)
|
|
337
337
|
raddr = (void *)NUM2ULONG(addr);
|
338
338
|
|
339
339
|
#ifdef __x86_64__
|
340
|
-
asm("
|
340
|
+
asm("push %%rbx;"
|
341
|
+
"push %%rdi;"
|
342
|
+
"push %%rsi;"
|
343
|
+
"push %%r12;"
|
344
|
+
"push %%r13;"
|
345
|
+
"push %%r14;"
|
346
|
+
"push %%r15;"
|
347
|
+
"mov %1, %%rax;"
|
341
348
|
"call *%2;"
|
342
349
|
"mov %%rax, %0;"
|
350
|
+
"pop %%r15;"
|
351
|
+
"pop %%r14;"
|
352
|
+
"pop %%r13;"
|
353
|
+
"pop %%r12;"
|
354
|
+
"pop %%rsi;"
|
355
|
+
"pop %%rdi;"
|
356
|
+
"pop %%rbx;"
|
343
357
|
: "=r"(rc)
|
344
358
|
: "r"(args), "r"(raddr)
|
345
359
|
: "%rax", "%rbx");
|
@@ -427,13 +441,15 @@ body(uintptr_t *regbuf)
|
|
427
441
|
void
|
428
442
|
ytl_backtrace(VALUE rip,
|
429
443
|
VALUE rax, VALUE rcx, VALUE rdx, VALUE rbx,
|
430
|
-
VALUE rbp, VALUE rsp, VALUE rdi, VALUE rsi
|
431
|
-
|
432
|
-
VALUE
|
444
|
+
VALUE rbp, VALUE rsp, VALUE rdi, VALUE rsi
|
445
|
+
#ifdef __x86_64__
|
446
|
+
, VALUE r8, VALUE r9, VALUE r10, VALUE r11,
|
447
|
+
VALUE r12, VALUE r13, VALUE r14, VALUE r15
|
448
|
+
#endif
|
449
|
+
)
|
433
450
|
{
|
434
451
|
VALUE *argv;
|
435
452
|
uintptr_t sp;
|
436
|
-
int i;
|
437
453
|
|
438
454
|
argv = ALLOCA_N(VALUE, NUMREGS + 1);
|
439
455
|
|
@@ -445,6 +461,7 @@ ytl_backtrace(VALUE rip,
|
|
445
461
|
argv[5] = ULONG2NUM(rbp);
|
446
462
|
argv[6] = ULONG2NUM(rdi);
|
447
463
|
argv[7] = ULONG2NUM(rsi);
|
464
|
+
#ifdef __x86_64__
|
448
465
|
argv[8] = ULONG2NUM(r8);
|
449
466
|
argv[9] = ULONG2NUM(r9);
|
450
467
|
argv[10] = ULONG2NUM(r10);
|
@@ -453,6 +470,7 @@ ytl_backtrace(VALUE rip,
|
|
453
470
|
argv[13] = ULONG2NUM(r13);
|
454
471
|
argv[14] = ULONG2NUM(r14);
|
455
472
|
argv[15] = ULONG2NUM(r15);
|
473
|
+
#endif
|
456
474
|
sp = (uintptr_t)rsp;
|
457
475
|
sp += NUMREGS * sizeof(uintptr_t); /* reg save area */
|
458
476
|
sp += sizeof(uintptr_t); /* stored pc by call instruction */
|
@@ -613,6 +631,8 @@ ytl_ivar_set_boxing(VALUE slf, int off, VALUE val)
|
|
613
631
|
}
|
614
632
|
}
|
615
633
|
ROBJECT_IVPTR(slf)[off] = val;
|
634
|
+
|
635
|
+
return val;
|
616
636
|
}
|
617
637
|
|
618
638
|
void
|
@@ -670,6 +690,13 @@ Init_ytljit_ext()
|
|
670
690
|
rb_define_method(ytl_cArena, "raw_address", ytl_arena_raw_address, 0);
|
671
691
|
rb_define_method(ytl_cArena, "to_s", ytl_arena_to_s, 0);
|
672
692
|
|
693
|
+
ytl_cThread = rb_define_class_under(ytl_mRuntime, "Thread", rb_cObject);
|
694
|
+
rb_define_method(ytl_cThread, "_join", ytl_thread_join, 0);
|
695
|
+
rb_define_method(ytl_cThread, "_merge", ytl_thread_merge, 1);
|
696
|
+
rb_define_method(ytl_cThread, "pself", ytl_thread_pself, 0);
|
697
|
+
rb_define_method(ytl_cThread, "pself=", ytl_thread_set_pself, 1);
|
698
|
+
rb_define_method(ytl_cThread, "cself", ytl_thread_cself, 0);
|
699
|
+
|
673
700
|
/* Open Handles */
|
674
701
|
#ifdef __CYGWIN__
|
675
702
|
OPEN_CHECK(dl_handles[used_dl_handles] = dlopen("cygwin1.dll", RTLD_LAZY));
|
data/ext/ytljit.h
CHANGED
@@ -316,3 +316,36 @@ typedef struct {
|
|
316
316
|
} rb_binding_t;
|
317
317
|
|
318
318
|
rb_iseq_t *rb_method_get_iseq(VALUE method);
|
319
|
+
|
320
|
+
#ifndef RCLASS_M_TBL
|
321
|
+
#define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
|
322
|
+
#endif
|
323
|
+
|
324
|
+
#ifndef RCLASS_SUPER
|
325
|
+
#define RCLASS_SUPER(c) (RCLASS(c)->ptr->super)
|
326
|
+
#endif
|
327
|
+
|
328
|
+
#ifndef RCLASS_IV_INDEX_TBL
|
329
|
+
#define RCLASS_IV_INDEX_TBL(c) (RCLASS(c)->iv_index_tbl)
|
330
|
+
#endif
|
331
|
+
|
332
|
+
#ifndef ROBJECT_NUMIV
|
333
|
+
#define ROBJECT_NUMIV(o) \
|
334
|
+
((RBASIC(o)->flags & ROBJECT_EMBED) ? \
|
335
|
+
ROBJECT_EMBED_LEN_MAX : \
|
336
|
+
ROBJECT(o)->as.heap.numiv)
|
337
|
+
#endif
|
338
|
+
|
339
|
+
#ifndef ROBJECT_IVPTR
|
340
|
+
#define ROBJECT_IVPTR(o) \
|
341
|
+
((RBASIC(o)->flags & ROBJECT_EMBED) ? \
|
342
|
+
ROBJECT(o)->as.ary : \
|
343
|
+
ROBJECT(o)->as.heap.ivptr)
|
344
|
+
#endif
|
345
|
+
|
346
|
+
#ifndef ROBJECT_IV_INDEX_TBL
|
347
|
+
#define ROBJECT_IV_INDEX_TBL(o) \
|
348
|
+
((RBASIC(o)->flags & ROBJECT_EMBED) ? \
|
349
|
+
RCLASS_IV_INDEX_TBL(rb_obj_class(o)) : \
|
350
|
+
ROBJECT(o)->as.heap.iv_index_tbl)
|
351
|
+
#endif
|
data/lib/ytljit.rb
CHANGED
data/lib/ytljit/asm.rb
CHANGED
@@ -24,6 +24,7 @@ module YTLJit
|
|
24
24
|
if frame_struct_tab[pc] then
|
25
25
|
STDERR.print frame_struct_tab[pc][0].class, "\n"
|
26
26
|
STDERR.print frame_struct_tab[pc][0].debug_info, "\n"
|
27
|
+
STDERR.print frame_struct_tab[pc][3], "\n"
|
27
28
|
STDERR.print frame_struct_tab[pc][2].map {|n| n.class}, "\n"
|
28
29
|
bp = memref(bp)
|
29
30
|
backtrace(bp)
|
@@ -36,6 +37,7 @@ module YTLJit
|
|
36
37
|
frame_struct_tab = VM::Node::TopTopNode.get_frame_struct_tab
|
37
38
|
STDERR.print frame_struct_tab[regval[1]][0].debug_info, "\n"
|
38
39
|
STDERR.print frame_struct_tab[regval[1]][2].map {|n| n.class}, "\n"
|
40
|
+
STDERR.print frame_struct_tab[regval[1]][3], "\n"
|
39
41
|
REGS.each do |rname, no|
|
40
42
|
STDERR.print rname
|
41
43
|
STDERR.print ": 0x"
|
@@ -177,16 +179,21 @@ module YTLJit
|
|
177
179
|
@retry_mode = org_retry_mode
|
178
180
|
end
|
179
181
|
|
182
|
+
def get_value_table_entity
|
183
|
+
@@value_table_entity
|
184
|
+
end
|
185
|
+
|
180
186
|
def add_value_entry(val)
|
181
187
|
off= nil
|
182
188
|
unless off = @@value_table_cache[val] then
|
183
189
|
off = @@value_table_entity.current_pos
|
184
190
|
@@value_table_entity.emit([val.value].pack("Q"))
|
185
191
|
stfunc = lambda {
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
192
|
+
value_table_entity = get_value_table_entity
|
193
|
+
oldpos = value_table_entity.current_pos
|
194
|
+
value_table_entity.current_pos = off
|
195
|
+
value_table_entity.emit([val.value].pack("Q"))
|
196
|
+
value_table_entity.current_pos = oldpos
|
190
197
|
}
|
191
198
|
val.add_refer(stfunc)
|
192
199
|
@@value_table_cache[val] = off
|
data/lib/ytljit/asmext_x64.rb
CHANGED
@@ -134,7 +134,7 @@ module YTLJit
|
|
134
134
|
offset = 8 + spos * 8
|
135
135
|
code += asm.update_state(gen.mov(TMPR, OpIndirect.new(SPR, offset)))
|
136
136
|
end
|
137
|
-
code += asm.update_state(gen.send(inst,
|
137
|
+
code += asm.update_state(gen.send(inst, dst, TMPR))
|
138
138
|
code
|
139
139
|
end
|
140
140
|
end
|
data/lib/ytljit/asmext_x86.rb
CHANGED
@@ -0,0 +1,136 @@
|
|
1
|
+
require '../../ext/ytljit_ext.so'
|
2
|
+
module YTLJit
|
3
|
+
|
4
|
+
=begin
|
5
|
+
Dynamic Method Search
|
6
|
+
using cuckoo hashing
|
7
|
+
=end
|
8
|
+
|
9
|
+
class CuckooHash
|
10
|
+
PRIMES = [
|
11
|
+
3,
|
12
|
+
5,
|
13
|
+
7,
|
14
|
+
8 + 3,
|
15
|
+
17,
|
16
|
+
16 + 3,
|
17
|
+
32 + 5,
|
18
|
+
64 + 3,
|
19
|
+
128 + 3,
|
20
|
+
256 + 27,
|
21
|
+
512 + 9,
|
22
|
+
1024 + 9,
|
23
|
+
2048 + 5,
|
24
|
+
4096 + 3,
|
25
|
+
8192 + 27,
|
26
|
+
16384 + 43,
|
27
|
+
32768 + 3,
|
28
|
+
65536 + 45,
|
29
|
+
131072 + 29,
|
30
|
+
262144 + 3,
|
31
|
+
524288 + 21,
|
32
|
+
1048576 + 7,
|
33
|
+
2097152 + 17,
|
34
|
+
4194304 + 15,
|
35
|
+
8388608 + 9,
|
36
|
+
16777216 + 43,
|
37
|
+
33554432 + 35,
|
38
|
+
67108864 + 15,
|
39
|
+
134217728 + 29,
|
40
|
+
268435456 + 3,
|
41
|
+
536870912 + 11,
|
42
|
+
1073741824 + 85,
|
43
|
+
0
|
44
|
+
]
|
45
|
+
|
46
|
+
def initialize(elements)
|
47
|
+
es = elements.size
|
48
|
+
@plimepos = 0
|
49
|
+
PRIMES.each_with_index do |n, i|
|
50
|
+
if es / 2 < n then
|
51
|
+
@primepos = i
|
52
|
+
break
|
53
|
+
end
|
54
|
+
end
|
55
|
+
@tabsizea = PRIMES[@primepos]
|
56
|
+
@tabsizeb = PRIMES[@primepos - 1]
|
57
|
+
|
58
|
+
@value = [Array.new(@tabsizea), Array.new(@tabsizeb)]
|
59
|
+
@key = [Array.new(@tabsizea), Array.new(@tabsizeb)]
|
60
|
+
@hfunc = [gen_hash_function_a(@tabsizea), gen_hash_function_b(@tabsizeb)]
|
61
|
+
fill(elements)
|
62
|
+
end
|
63
|
+
|
64
|
+
def fill(elements)
|
65
|
+
elements.each do |key, value|
|
66
|
+
keyadd = ((key.__id__ >> 1) << 2)
|
67
|
+
insert(keyadd, value)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
def insert(keyadd, value)
|
71
|
+
while true
|
72
|
+
@tabsizea.times do
|
73
|
+
hv = @hfunc[0].call(keyadd)
|
74
|
+
|
75
|
+
vala = @value[0][hv]
|
76
|
+
keyadda = @key[0][hv]
|
77
|
+
@value[0][hv] = value
|
78
|
+
@key[0][hv] = keyadd
|
79
|
+
if vala == nil then
|
80
|
+
return true
|
81
|
+
end
|
82
|
+
keyadd = keyadda
|
83
|
+
|
84
|
+
hv = @hfunc[1].call(keyadd)
|
85
|
+
valb = @value[1][hv]
|
86
|
+
keyaddb = @key[1][hv]
|
87
|
+
@value[1][hv] = vala
|
88
|
+
@key[1][hv] = keyadd
|
89
|
+
if valb == nil then
|
90
|
+
return true
|
91
|
+
end
|
92
|
+
keyadd = keyaddb
|
93
|
+
value = valb
|
94
|
+
end
|
95
|
+
|
96
|
+
rehash
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def rehash
|
101
|
+
ovalue = @value
|
102
|
+
okey = @key
|
103
|
+
if @tabsizea == @tabsizeb then
|
104
|
+
@primepos += 1
|
105
|
+
@tabsizea = PRIMES[@primepos]
|
106
|
+
else
|
107
|
+
@tabsizeb = PRIMES[@primepos]
|
108
|
+
end
|
109
|
+
@value = [Array.new(@tabsizea), Array.new(@tabsizeb)]
|
110
|
+
@key = [Array.new(@tabsizea), Array.new(@tabsizeb)]
|
111
|
+
@hfunc = [gen_hash_function_a(@tabsizea), gen_hash_function_b(@tabsizeb)]
|
112
|
+
[0, 1].each do |n|
|
113
|
+
okey[n].each_with_index do |ele, i|
|
114
|
+
if ele then
|
115
|
+
insert(ele, ovalue[n][i])
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def gen_hash_function_a(size)
|
122
|
+
lambda {|v|
|
123
|
+
(v / 20 + v) % size
|
124
|
+
}
|
125
|
+
end
|
126
|
+
|
127
|
+
def gen_hash_function_b(size)
|
128
|
+
lambda {|v|
|
129
|
+
((v / 21) + v * 31) % size
|
130
|
+
}
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
a = YTLJit::CuckooHash.new({})
|
136
|
+
p a.gen_hash_function_b(100).to_iseq.to_a
|