ytljit 0.0.1

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.
Files changed (47) hide show
  1. data/README +29 -0
  2. data/Rakefile +22 -0
  3. data/ext/code_alloc.c +266 -0
  4. data/ext/extconf.rb +3 -0
  5. data/ext/ytljit.c +527 -0
  6. data/ext/ytljit.h +285 -0
  7. data/lib/ytljit/asm.rb +205 -0
  8. data/lib/ytljit/asmext.rb +199 -0
  9. data/lib/ytljit/asmext_x64.rb +212 -0
  10. data/lib/ytljit/asmext_x86.rb +128 -0
  11. data/lib/ytljit/asmutil.rb +182 -0
  12. data/lib/ytljit/codespace.rb +92 -0
  13. data/lib/ytljit/error.rb +7 -0
  14. data/lib/ytljit/instruction.rb +138 -0
  15. data/lib/ytljit/instruction_ia.rb +1298 -0
  16. data/lib/ytljit/instruction_x64.rb +41 -0
  17. data/lib/ytljit/instruction_x86.rb +11 -0
  18. data/lib/ytljit/marshal.rb +133 -0
  19. data/lib/ytljit/matcher.rb +235 -0
  20. data/lib/ytljit/rubyvm.rb +63 -0
  21. data/lib/ytljit/struct.rb +125 -0
  22. data/lib/ytljit/type.rb +112 -0
  23. data/lib/ytljit/util.rb +63 -0
  24. data/lib/ytljit/vm.rb +1649 -0
  25. data/lib/ytljit/vm_codegen.rb +491 -0
  26. data/lib/ytljit/vm_inline_method.rb +85 -0
  27. data/lib/ytljit/vm_inspect.rb +74 -0
  28. data/lib/ytljit/vm_sendnode.rb +561 -0
  29. data/lib/ytljit/vm_trans.rb +508 -0
  30. data/lib/ytljit/vm_type.rb +299 -0
  31. data/lib/ytljit/vm_type_gen.rb +158 -0
  32. data/lib/ytljit/vm_typeinf.rb +98 -0
  33. data/lib/ytljit.rb +46 -0
  34. data/test/asmsample.rb +117 -0
  35. data/test/cstest.rb +61 -0
  36. data/test/marshaltest.rb +27 -0
  37. data/test/test_assemble.rb +148 -0
  38. data/test/test_assemble2.rb +286 -0
  39. data/test/test_codespace.rb +102 -0
  40. data/test/test_typeinf.rb +21 -0
  41. data/test/tivmtest.rb +54 -0
  42. data/test/vmtest.rb +59 -0
  43. data/test/vmtest2.rb +41 -0
  44. data/test/vmtest3.rb +22 -0
  45. data/test/vmtest_compile_only.rb +41 -0
  46. data/test/vmtest_execute_only.rb +22 -0
  47. metadata +121 -0
data/ext/ytljit.c ADDED
@@ -0,0 +1,527 @@
1
+ #include <setjmp.h>
2
+ #include <dlfcn.h>
3
+ #include <unistd.h>
4
+ #include <stdlib.h>
5
+ #include "ruby.h"
6
+
7
+ #include "ytljit.h"
8
+
9
+ VALUE ytl_mYTLJit;
10
+ VALUE ytl_cCodeSpace;
11
+ VALUE ytl_cValueSpace;
12
+ VALUE ytl_cStepHandler;
13
+ VALUE ytl_eStepHandler;
14
+ static ID ytl_v_step_handler_id;
15
+
16
+ static void *dl_handles[MAX_DL_HANDLES];
17
+ static int used_dl_handles = 0;
18
+
19
+ VALUE
20
+ ytl_address_of(VALUE self, VALUE symstr)
21
+ {
22
+ int i;
23
+ char *sym;
24
+ void *add;
25
+
26
+ sym = StringValuePtr(symstr);
27
+ for (i = 0; i < used_dl_handles; i++) {
28
+ if ((add = dlsym(dl_handles[i], sym)) != NULL) {
29
+ return ULONG2NUM((uintptr_t)add);
30
+ }
31
+ }
32
+
33
+ return Qnil;
34
+ }
35
+
36
+ VALUE
37
+ ytl_method_address_of(VALUE klass, VALUE mname)
38
+ {
39
+ rb_method_entry_t *me;
40
+ ID mid = SYM2ID(mname);
41
+
42
+ me = rb_method_entry(klass, mid);
43
+
44
+ if (me && me->def && me->def->type == VM_METHOD_TYPE_CFUNC) {
45
+ return ULONG2NUM((uintptr_t)me->def->body.cfunc.func);
46
+ }
47
+ else {
48
+ return Qnil;
49
+ }
50
+ }
51
+
52
+ VALUE
53
+ ytl_instance_var_address_of(VALUE slf, VALUE ivname)
54
+ {
55
+ ID ivid = SYM2ID(ivname);
56
+ struct st_table *iv_index_tbl;
57
+ VALUE *valadd, *ptr;
58
+ long len;
59
+ st_data_t index;
60
+
61
+ len = ROBJECT_NUMIV(slf);
62
+ ptr = ROBJECT_IVPTR(slf);
63
+ iv_index_tbl = ROBJECT_IV_INDEX_TBL(slf);
64
+ if (!iv_index_tbl) return Qnil;
65
+ if (!st_lookup(iv_index_tbl, (st_data_t)ivid, &index)) return Qnil;
66
+ if (len <= (long)index) return Qnil;
67
+ valadd = &ptr[index];
68
+ return ULONG2NUM((uintptr_t)valadd);
69
+ }
70
+
71
+ void *
72
+ ytl_method_address_of_raw(VALUE klass, VALUE mname)
73
+ {
74
+ rb_method_entry_t *me;
75
+ ID mid = SYM2ID(mname);
76
+
77
+ me = rb_method_entry(klass, mid);
78
+
79
+ if (me && me->def && me->def->type == VM_METHOD_TYPE_CFUNC) {
80
+ return (void *)me->def->body.cfunc.func;
81
+ }
82
+ else {
83
+ return NULL;
84
+ }
85
+ }
86
+
87
+ VALUE
88
+ ytl_binding_to_a(VALUE self)
89
+ {
90
+ rb_proc_t *proc;
91
+ rb_binding_t *bptr;
92
+ rb_env_t *env;
93
+ VALUE resary;
94
+ VALUE eleary;
95
+ VALUE tmpenv;
96
+ int i;
97
+
98
+ GetBindingPtr(self, bptr);
99
+
100
+ resary = rb_ary_new();
101
+
102
+ tmpenv = bptr->env;
103
+ while (tmpenv) {
104
+ GetEnvPtr(tmpenv, env);
105
+ eleary = rb_ary_new();
106
+ rb_ary_push(eleary, env->block.self);
107
+
108
+ for (i = 0; i <= env->local_size; i++) {
109
+ rb_ary_push(eleary, env->env[i]);
110
+ }
111
+ rb_ary_push(resary, eleary);
112
+
113
+ tmpenv = env->prev_envval;
114
+ }
115
+
116
+ return resary;
117
+ }
118
+
119
+ VALUE
120
+ ytl_binding_variables(VALUE self)
121
+ {
122
+ rb_binding_t *bptr;
123
+ rb_env_t *env;
124
+ rb_iseq_t *iseq;
125
+ VALUE resary;
126
+ VALUE eleary;
127
+ VALUE tmpenv;
128
+ int i;
129
+
130
+ GetBindingPtr(self, bptr);
131
+
132
+ resary = rb_ary_new();
133
+
134
+ tmpenv = bptr->env;
135
+ while (tmpenv) {
136
+ GetEnvPtr(tmpenv, env);
137
+ eleary = rb_ary_new();
138
+ iseq = env->block.iseq;
139
+ if (iseq) {
140
+ for (i = 0; i < iseq->local_table_size; i++) {
141
+ ID lid = iseq->local_table[i];
142
+ if (rb_is_local_id(lid)) {
143
+ rb_ary_push(eleary, ID2SYM(lid));
144
+ }
145
+ }
146
+ }
147
+
148
+ rb_ary_push(resary, eleary);
149
+ tmpenv = env->prev_envval;
150
+ }
151
+
152
+ return resary;
153
+ }
154
+
155
+
156
+ VALUE
157
+ ytl_proc_to_iseq(VALUE self)
158
+ {
159
+ rb_proc_t *proc;
160
+ rb_iseq_t *iseq;
161
+
162
+ GetProcPtr(self, proc);
163
+ iseq = proc->block.iseq;
164
+ if (proc->is_from_method) {
165
+ NODE *node = (NODE *)iseq;
166
+ /* method(:foo).to_proc */
167
+ iseq = rb_method_get_iseq(node->u2.value);
168
+ }
169
+ if (iseq) {
170
+ return iseq->self;
171
+ }
172
+ else {
173
+ return Qnil;
174
+ }
175
+ }
176
+
177
+ VALUE
178
+ ytl_proc_copy(VALUE self, VALUE procval)
179
+ {
180
+ rb_proc_t *src, *dst;
181
+ GetProcPtr(procval, src);
182
+ GetProcPtr(self, dst);
183
+
184
+ dst->block = src->block;
185
+ dst->block.proc = procval;
186
+ dst->blockprocval = src->blockprocval;
187
+ dst->envval = src->envval;
188
+ dst->safe_level = src->safe_level;
189
+ dst->is_lambda = src->is_lambda;
190
+
191
+ return self;
192
+ }
193
+
194
+ VALUE
195
+ ytl_memref(VALUE self, VALUE addr)
196
+ {
197
+ return UINT2NUM(*((char *)NUM2LONG(addr)));
198
+ }
199
+
200
+ VALUE
201
+ ytl_code_space_allocate(VALUE klass)
202
+ {
203
+ struct CodeSpace *obj;
204
+
205
+ obj = csalloc(INIT_CODE_SPACE_SIZE);
206
+ obj->size = INIT_CODE_SPACE_SIZE - sizeof(struct CodeSpace);
207
+ obj->used = 0;
208
+ return Data_Wrap_Struct(klass, NULL, csfree, (void *)obj);
209
+ }
210
+
211
+ VALUE
212
+ ytl_value_space_allocate(VALUE klass)
213
+ {
214
+ struct CodeSpace *obj;
215
+
216
+ obj = csalloc(VALUE_SPACE_SIZE);
217
+ obj->size = VALUE_SPACE_SIZE - sizeof(struct CodeSpace);
218
+ obj->used = 0;
219
+ return Data_Wrap_Struct(klass, NULL, csfree, (void *)obj);
220
+ }
221
+
222
+ VALUE
223
+ ytl_code_space_emit(VALUE self, VALUE offset, VALUE src)
224
+ {
225
+ struct CodeSpace *raw_cs;
226
+ char *src_ptr;
227
+ size_t src_len;
228
+ int raw_offset;
229
+ size_t cooked_offset;
230
+ struct RData *data_cs;
231
+
232
+ raw_cs = (struct CodeSpace *)DATA_PTR(self);
233
+ src_ptr = RSTRING_PTR(src);
234
+ src_len = RSTRING_LEN(src);
235
+ raw_offset = FIX2INT(offset);
236
+ cooked_offset = raw_offset;
237
+ if (raw_offset < 0) {
238
+ cooked_offset = raw_cs->used - raw_offset + 1;
239
+ }
240
+
241
+ while (raw_cs->size <= src_len + cooked_offset + 4) {
242
+ size_t newsize = (raw_cs->size + sizeof(struct CodeSpace)) * 2;
243
+ void *new_cs = csalloc(newsize);
244
+
245
+ //*(struct CodeSpace *)new_cs = *(struct CodeSpace *)raw_cs;
246
+ memcpy(new_cs, raw_cs, newsize / 2);
247
+ csfree(raw_cs);
248
+ raw_cs = new_cs;
249
+ raw_cs->size = newsize - sizeof(struct CodeSpace);
250
+ }
251
+
252
+ memcpy(raw_cs->body + cooked_offset, src_ptr, src_len);
253
+ if (raw_cs->used < cooked_offset + src_len) {
254
+ raw_cs->used = cooked_offset + src_len;
255
+ }
256
+ data_cs = (struct RData *)self;
257
+ data_cs->data = raw_cs;
258
+
259
+ return src;
260
+ }
261
+
262
+ VALUE
263
+ ytl_code_space_ref(VALUE self, VALUE offset)
264
+ {
265
+ struct CodeSpace *raw_cs;
266
+
267
+ int raw_offset;
268
+ size_t cooked_offset;
269
+
270
+ raw_cs = (struct CodeSpace *)DATA_PTR(self);
271
+ raw_offset = FIX2INT(offset);
272
+ cooked_offset = raw_offset;
273
+ if (raw_offset < 0) {
274
+ size_t rev_offset = -raw_offset;
275
+ cooked_offset = raw_cs->used + rev_offset + 1;
276
+ }
277
+
278
+ return INT2FIX(raw_cs->body[cooked_offset]);
279
+ }
280
+
281
+ VALUE
282
+ ytl_code_current_pos(VALUE self)
283
+ {
284
+ struct CodeSpace *raw_cs;
285
+
286
+ raw_cs = (struct CodeSpace *)DATA_PTR(self);
287
+ return INT2NUM(raw_cs->used);
288
+ }
289
+
290
+ VALUE
291
+ ytl_code_set_current_pos(VALUE self, VALUE val)
292
+ {
293
+ struct CodeSpace *raw_cs;
294
+
295
+ raw_cs = (struct CodeSpace *)DATA_PTR(self);
296
+ raw_cs->used = NUM2INT(val);
297
+ return val;
298
+ }
299
+
300
+ VALUE
301
+ ytl_code_base_address(VALUE self)
302
+ {
303
+ struct CodeSpace *raw_cs;
304
+
305
+ raw_cs = (struct CodeSpace *)DATA_PTR(self);
306
+ return ULONG2NUM((unsigned long)raw_cs->body);
307
+ }
308
+
309
+ VALUE
310
+ ytl_code_call(int argc, VALUE *argv, VALUE self)
311
+ {
312
+ VALUE addr;
313
+ VALUE args;
314
+ VALUE rc;
315
+ void *raddr;
316
+
317
+ rb_scan_args(argc, argv, "11", &addr, &args);
318
+ raddr = (void *)NUM2ULONG(addr);
319
+
320
+ #ifdef __x86_64__
321
+ asm("mov %1, %%rax;"
322
+ "call *%2;"
323
+ "mov %%rax, %0;"
324
+ : "=r"(rc)
325
+ : "r"(args), "r"(raddr)
326
+ : "%rax", "%rbx");
327
+ #elif __CYGWIN__
328
+ asm("mov %1, %%eax;"
329
+ "call *%2;"
330
+ "mov %%eax, %0;"
331
+ : "=r"(rc)
332
+ : "r"(args), "r"(raddr)
333
+ : "%eax", "%ebx");
334
+ #elif __i386__
335
+ /* push %ebx ? */
336
+ asm("mov %1, %%eax;"
337
+ "call *%2;"
338
+ "mov %%eax, %0;"
339
+ : "=r"(rc)
340
+ : "r"(args), "r"(raddr)
341
+ : "%eax");
342
+ /* pop %ebx ? */
343
+ #else
344
+ #error "only i386 or x86-64 is supported"
345
+ #endif
346
+
347
+ return rc;
348
+ }
349
+
350
+ VALUE
351
+ ytl_code_space_code(VALUE self)
352
+ {
353
+ struct CodeSpace *raw_cs;
354
+
355
+ raw_cs = (struct CodeSpace *)DATA_PTR(self);
356
+
357
+ return rb_str_new(raw_cs->body, raw_cs->used);
358
+ }
359
+
360
+ VALUE
361
+ ytl_code_space_to_s(VALUE self)
362
+ {
363
+ struct CodeSpace *raw_cs;
364
+
365
+ raw_cs = (struct CodeSpace *)DATA_PTR(self);
366
+
367
+ return rb_sprintf("#<codeSpace %p base=%p:...>", (void *)self, (void *)raw_cs->body);
368
+ }
369
+
370
+ VALUE
371
+ ytl_value_space_to_s(VALUE self)
372
+ {
373
+ struct CodeSpace *raw_cs;
374
+
375
+ raw_cs = (struct CodeSpace *)DATA_PTR(self);
376
+
377
+ return rb_sprintf("#<valueSpace %p base=%p:...>", (void *)self, (void *)raw_cs->body);
378
+ }
379
+
380
+ static VALUE *
381
+ get_registers(unsigned long *regs, VALUE *argv)
382
+ {
383
+ argv[0] = ULONG2NUM((unsigned long)__builtin_return_address(1));
384
+
385
+ /* regs[0] old bp
386
+ regs[-1] old ebx (maybe gcc depend)
387
+ regs[-2] return address
388
+ regs[-3] pusha starts
389
+ */
390
+ argv[1] = ULONG2NUM(regs[-3]); /* eax */
391
+ argv[2] = ULONG2NUM(regs[-4]); /* ecx */
392
+ argv[3] = ULONG2NUM(regs[-5]); /* edx */
393
+ argv[4] = ULONG2NUM(regs[-6]); /* ebx */
394
+ argv[5] = ULONG2NUM(regs[-7]); /* ebp */
395
+ argv[6] = ULONG2NUM(regs[-8]); /* esi */
396
+ argv[7] = ULONG2NUM(regs[-9]); /* edi */
397
+
398
+ return argv;
399
+ }
400
+
401
+ static void
402
+ body(void)
403
+ {
404
+ VALUE *argv;
405
+ unsigned long *regs;
406
+
407
+ #if defined(__i386__) || defined(__i386)
408
+ asm("mov (%%ebp), %0"
409
+ : "=r" (regs) : : "%eax");
410
+ #elif defined(__x86_64__) || defined(__x86_64)
411
+ asm("mov (%%rbp), %0"
412
+ : "=r" (regs) : : "%rax");
413
+ #else
414
+ #error "only i386 or x86-64 is supported"
415
+ #endif
416
+ argv = ALLOCA_N(VALUE, 8);
417
+ argv = get_registers(regs, argv);
418
+
419
+ rb_funcall2(ytl_eStepHandler, ytl_v_step_handler_id, 8, argv);
420
+ }
421
+
422
+ static void
423
+ pushall(void)
424
+ {
425
+ #ifdef __x86_64__
426
+ asm("push %rax");
427
+ asm("push %rcx");
428
+ asm("push %rdx");
429
+ asm("push %rbx");
430
+ asm("push %rbp");
431
+ asm("push %rsi");
432
+ asm("push %rdi");
433
+ #elif __i386__
434
+ asm("pushal");
435
+ #else
436
+ #error "only i386 or x86-64 is supported"
437
+ #endif
438
+ }
439
+
440
+ static void
441
+ popall(void)
442
+ {
443
+ #ifdef __x86_64__
444
+ asm("pop %rdi");
445
+ asm("pop %rsi");
446
+ asm("pop %rbp");
447
+ asm("pop %rbx");
448
+ asm("pop %rdx");
449
+ asm("pop %rcx");
450
+ asm("pop %rax");
451
+ #elif __i386__
452
+ asm("popal");
453
+ #else
454
+ #error "only i386 or x86-64 is supported"
455
+ #endif
456
+ }
457
+
458
+ void
459
+ ytl_step_handler()
460
+ {
461
+
462
+ /* Don't add local variables. Maybe break consistency of stack */
463
+
464
+ pushall();
465
+ body();
466
+ popall();
467
+ }
468
+
469
+ void
470
+ Init_ytljit_ext()
471
+ {
472
+ VALUE *argv;
473
+
474
+ init_csarena();
475
+
476
+ ytl_mYTLJit = rb_define_module("YTLJit");
477
+
478
+ rb_define_module_function(ytl_mYTLJit, "address_of", ytl_address_of, 1);
479
+ rb_define_module_function(rb_cObject, "method_address_of",
480
+ ytl_method_address_of, 1);
481
+ rb_define_method(rb_cObject, "instance_var_address_of",
482
+ ytl_instance_var_address_of, 1);
483
+ rb_define_module_function(ytl_mYTLJit, "memref", ytl_memref, 1);
484
+
485
+ rb_define_method(rb_cBinding, "to_a", ytl_binding_to_a, 0);
486
+ rb_define_method(rb_cBinding, "variables", ytl_binding_variables, 0);
487
+
488
+ rb_define_method(rb_cProc, "to_iseq", ytl_proc_to_iseq, 0);
489
+ rb_define_method(rb_cProc, "copy", ytl_proc_copy, 1);
490
+
491
+ ytl_v_step_handler_id = rb_intern("step_handler");
492
+
493
+ ytl_cStepHandler = rb_define_class_under(ytl_mYTLJit, "StepHandler", rb_cObject);
494
+ argv = ALLOCA_N(VALUE, 1);
495
+ ytl_eStepHandler = rb_class_new_instance(0, argv, ytl_cStepHandler);
496
+ rb_global_variable(&ytl_eStepHandler);
497
+
498
+ ytl_cCodeSpace = rb_define_class_under(ytl_mYTLJit, "CodeSpace", rb_cObject);
499
+ rb_define_alloc_func(ytl_cCodeSpace, ytl_code_space_allocate);
500
+ rb_define_method(ytl_cCodeSpace, "[]=", ytl_code_space_emit, 2);
501
+ rb_define_method(ytl_cCodeSpace, "[]", ytl_code_space_ref, 1);
502
+ rb_define_method(ytl_cCodeSpace, "current_pos", ytl_code_current_pos, 0);
503
+ rb_define_method(ytl_cCodeSpace, "current_pos=", ytl_code_set_current_pos, 1);
504
+ rb_define_method(ytl_cCodeSpace, "base_address", ytl_code_base_address, 0);
505
+ rb_define_method(ytl_cCodeSpace, "call", ytl_code_call, -1);
506
+ rb_define_method(ytl_cCodeSpace, "code", ytl_code_space_code, 0);
507
+ rb_define_method(ytl_cCodeSpace, "to_s", ytl_code_space_to_s, 0);
508
+
509
+ ytl_cValueSpace =
510
+ rb_define_class_under(ytl_mYTLJit, "ValueSpace", ytl_cCodeSpace);
511
+ rb_define_alloc_func(ytl_cValueSpace, ytl_value_space_allocate);
512
+ rb_define_method(ytl_cValueSpace, "to_s", ytl_value_space_to_s, 0);
513
+
514
+ /* Open Handles */
515
+ #ifdef __CYGWIN__
516
+ OPEN_CHECK(dl_handles[used_dl_handles] = dlopen("cygwin1.dll", RTLD_LAZY));
517
+ used_dl_handles++;
518
+ OPEN_CHECK(dl_handles[used_dl_handles] = dlopen("cygruby191.dll", RTLD_LAZY));
519
+ used_dl_handles++;
520
+ OPEN_CHECK(dl_handles[used_dl_handles] = dlopen("ytljit.so", RTLD_LAZY));
521
+ used_dl_handles++;
522
+ #else
523
+ OPEN_CHECK(dl_handles[used_dl_handles] = dlopen(NULL, RTLD_LAZY));
524
+ used_dl_handles++;
525
+ #endif
526
+ }
527
+