ytljit 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+