plessl-llvmruby 0.0.3
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/COPYING +21 -0
- data/README +76 -0
- data/Rakefile +31 -0
- data/ext/extconf.rb +14 -0
- data/ext/llvm_basicblock.cpp +299 -0
- data/ext/llvm_function.cpp +48 -0
- data/ext/llvm_instruction.cpp +259 -0
- data/ext/llvm_module.cpp +189 -0
- data/ext/llvm_use.cpp +9 -0
- data/ext/llvm_user.cpp +71 -0
- data/ext/llvm_value.cpp +254 -0
- data/ext/llvmruby.c +328 -0
- data/ext/llvmruby.h +73 -0
- data/lib/llvm.rb +146 -0
- data/lib/ruby_vm.rb +352 -0
- data/lib/version.rb +11 -0
- data/test/byteswap.bc +0 -0
- data/test/test_basic.rb +340 -0
- data/test/test_basic_block.rb +80 -0
- data/test/test_instructions.rb +112 -0
- data/test/test_read_bitcode.rb +38 -0
- data/test/test_ruby_vm.rb +172 -0
- data/test/test_user.rb +72 -0
- data/test/test_value.rb +63 -0
- metadata +87 -0
data/ext/llvmruby.h
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
#define __STDC_LIMIT_MACROS
|
2
|
+
|
3
|
+
#include "llvm/Module.h"
|
4
|
+
#include "llvm/DerivedTypes.h"
|
5
|
+
#include "llvm/Constants.h"
|
6
|
+
#include "llvm/Instructions.h"
|
7
|
+
#include "llvm/ModuleProvider.h"
|
8
|
+
#include "llvm/PassManager.h"
|
9
|
+
#include "llvm/LinkAllPasses.h"
|
10
|
+
#include "llvm/Target/TargetData.h"
|
11
|
+
#include "llvm/Transforms/Scalar.h"
|
12
|
+
#include "llvm/Analysis/Verifier.h"
|
13
|
+
#include "llvm/ExecutionEngine/JIT.h"
|
14
|
+
#include "llvm/ExecutionEngine/Interpreter.h"
|
15
|
+
#include "llvm/ExecutionEngine/GenericValue.h"
|
16
|
+
#include "llvm/Support/IRBuilder.h"
|
17
|
+
#include <iostream>
|
18
|
+
using namespace llvm;
|
19
|
+
|
20
|
+
#include "ruby.h"
|
21
|
+
|
22
|
+
extern VALUE cLLVMRuby;
|
23
|
+
extern VALUE cLLVMValue;
|
24
|
+
extern VALUE cLLVMUser;
|
25
|
+
extern VALUE cLLVMUse;
|
26
|
+
extern VALUE cLLVMModule;
|
27
|
+
extern VALUE cLLVMFunction;
|
28
|
+
extern VALUE cLLVMBasicBlock;
|
29
|
+
extern VALUE cLLVMBuilder;
|
30
|
+
extern VALUE cLLVMType;
|
31
|
+
extern VALUE cLLVMPointerType;
|
32
|
+
extern VALUE cLLVMStructType;
|
33
|
+
extern VALUE cLLVMArrayType;
|
34
|
+
extern VALUE cLLVMVectorType;
|
35
|
+
extern VALUE cLLVMFunctionType;
|
36
|
+
extern VALUE cLLVMInstruction;
|
37
|
+
extern VALUE cLLVMBinaryOperator;
|
38
|
+
extern VALUE cLLVMAllocationInst;
|
39
|
+
|
40
|
+
#define HANDLE_TERM_INST(Num, Opcode, Klass) extern VALUE cLLVM##Klass;
|
41
|
+
#define HANDLE_MEMORY_INST(Num, Opcode, Klass) extern VALUE cLLVM##Klass;
|
42
|
+
#define HANDLE_OTHER_INST(Num, Opcode, Klass) extern VALUE cLLVM##Klass;
|
43
|
+
#include "llvm/Instruction.def"
|
44
|
+
|
45
|
+
extern VALUE cLLVMBinaryOps;
|
46
|
+
extern VALUE cLLVMPhi;
|
47
|
+
extern VALUE cLLVMPassManager;
|
48
|
+
|
49
|
+
#define LLVM_VAL(obj) ((Value*)DATA_PTR(obj))
|
50
|
+
#define LLVM_USER(obj) ((User*)DATA_PTR(obj))
|
51
|
+
#define LLVM_USE(obj) ((Use*)DATA_PTR(obj))
|
52
|
+
#define LLVM_TYPE(obj) ((Type*)DATA_PTR(obj))
|
53
|
+
#define LLVM_FUNC_TYPE(obj) ((FunctionType*)DATA_PTR(obj))
|
54
|
+
#define LLVM_MODULE(obj) ((Module*)DATA_PTR(obj))
|
55
|
+
#define LLVM_FUNCTION(obj) ((Function*)DATA_PTR(obj))
|
56
|
+
#define LLVM_BASIC_BLOCK(obj) ((BasicBlock*)DATA_PTR(obj))
|
57
|
+
#define LLVM_INSTRUCTION(obj) ((Instruction*)DATA_PTR(obj))
|
58
|
+
#define LLVM_PHI(obj) ((PHINode*)DATA_PTR(obj))
|
59
|
+
|
60
|
+
#define CHECK_TYPE(val, klass)\
|
61
|
+
if(!rb_obj_is_kind_of(val, klass)) {\
|
62
|
+
rb_raise(rb_eTypeError, "wrong argument type: %s given, expected %s", rb_obj_classname(val), rb_class2name(klass));\
|
63
|
+
}
|
64
|
+
|
65
|
+
extern "C" {
|
66
|
+
VALUE llvm_value_wrap(Value*);
|
67
|
+
VALUE llvm_user_wrap(User*);
|
68
|
+
VALUE llvm_use_wrap(Use*);
|
69
|
+
VALUE llvm_function_wrap(Function*);
|
70
|
+
VALUE llvm_basic_block_wrap(BasicBlock*);
|
71
|
+
VALUE llvm_function_create_block(VALUE);
|
72
|
+
VALUE llvm_instruction_wrap(Instruction*);
|
73
|
+
}
|
data/lib/llvm.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'llvmruby'
|
2
|
+
|
3
|
+
class Fixnum
|
4
|
+
def llvm(type = LLVM::MACHINE_WORD)
|
5
|
+
LLVM::Value.get_constant(type, self)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class Float
|
10
|
+
def llvm
|
11
|
+
LLVM::Value.get_float_constant(self)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Object
|
16
|
+
def immediate
|
17
|
+
LLVM::Value.get_immediate_constant(self)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class LLVM::Value
|
22
|
+
def llvm
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def immediate
|
27
|
+
self
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module LLVM
|
32
|
+
# enum llvm::Type::TypeID
|
33
|
+
VoidTyID, FloatTyID, DoubleTyID, X86_FP80TyID, FP128TyID, PPC_FP128TyID, LabelTyID, IntegerTyID,
|
34
|
+
FunctionTyID, StructTyID, ArrayTyID, PointerTyID, OpaqueTyID, VectorTyID = (0..13).to_a
|
35
|
+
|
36
|
+
class Builder
|
37
|
+
def self.add_bin_op(op)
|
38
|
+
define_method(op.downcase) do |x, y|
|
39
|
+
bin_op(Instruction.const_get(op), x, y)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
bin_ops = ['Add', 'Sub', 'Mul', 'UDiv', 'SDiv', 'FDiv', 'URem', 'SRem', 'FRem']
|
44
|
+
bin_ops += ['Shl', 'LShr', 'AShr', 'And', 'Or', 'Xor']
|
45
|
+
bin_ops.each {|op| add_bin_op(op)}
|
46
|
+
|
47
|
+
Instruction.constants.grep(/^ICMP_/) do |pred|
|
48
|
+
define_method(pred.downcase) do |x, y|
|
49
|
+
icmp(Instruction.const_get(pred), x, y)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
Instruction.constants.grep(/^FCMP_/) do |pred|
|
54
|
+
define_method(pred.downcase) do |x, y|
|
55
|
+
fcmp(Instruction.const_get(pred), x, y)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.define_cast(name, inst)
|
60
|
+
define_method(name) do |val, dest_type|
|
61
|
+
cast(inst, val, dest_type)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
define_cast(:trunc, Instruction::Trunc)
|
66
|
+
define_cast(:zext, Instruction::ZExt)
|
67
|
+
define_cast(:sext, Instruction::SExt)
|
68
|
+
define_cast(:fp_to_si, Instruction::FPToSI)
|
69
|
+
define_cast(:fp_to_ui, Instruction::FPToUI)
|
70
|
+
define_cast(:ui_to_fp, Instruction::UIToFP)
|
71
|
+
define_cast(:si_to_fp, Instruction::SIToFP)
|
72
|
+
define_cast(:fp_trunc, Instruction::FPTrunc)
|
73
|
+
define_cast(:fp_ext, Instruction::FPExt)
|
74
|
+
define_cast(:ptr_to_int, Instruction::PtrToInt)
|
75
|
+
define_cast(:int_to_ptr, Instruction::IntToPtr)
|
76
|
+
define_cast(:bit_cast, Instruction::BitCast)
|
77
|
+
|
78
|
+
def write(&b)
|
79
|
+
instance_eval(&b)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# describe structures used by the ruby 1.8/1.9 interpreters
|
84
|
+
module RubyInternals
|
85
|
+
FIXNUM_FLAG = 0x1.llvm
|
86
|
+
CHAR = Type::Int8Ty
|
87
|
+
P_CHAR = Type::pointer(CHAR)
|
88
|
+
LONG = MACHINE_WORD
|
89
|
+
INT = Type::Int32Ty
|
90
|
+
VALUE = MACHINE_WORD
|
91
|
+
P_VALUE = Type::pointer(VALUE)
|
92
|
+
ID = MACHINE_WORD
|
93
|
+
RBASIC = Type::struct([VALUE, VALUE])
|
94
|
+
RARRAY = Type::struct([RBASIC, LONG, LONG, P_VALUE])
|
95
|
+
P_RARRAY = Type::pointer(RARRAY)
|
96
|
+
RSTRING = Type::struct([RBASIC, LONG, P_CHAR, VALUE])
|
97
|
+
P_RSTRING = Type::pointer(RSTRING)
|
98
|
+
end
|
99
|
+
|
100
|
+
# include this into the builder to get methods for manipulating ruby values
|
101
|
+
module RubyHelpers
|
102
|
+
include RubyInternals
|
103
|
+
|
104
|
+
def fixnum?(val)
|
105
|
+
self.and(FIXNUM_FLAG, val)
|
106
|
+
end
|
107
|
+
|
108
|
+
def num2fix(val)
|
109
|
+
shifted = shl(val, 1.llvm)
|
110
|
+
xor(FIXNUM_FLAG, shifted)
|
111
|
+
end
|
112
|
+
|
113
|
+
def fix2int(val)
|
114
|
+
x = xor(FIXNUM_FLAG, val)
|
115
|
+
lshr(val, 1.llvm)
|
116
|
+
end
|
117
|
+
|
118
|
+
def slen(str)
|
119
|
+
val_ptr = int_to_ptr(str, P_RSTRING)
|
120
|
+
len_ptr = struct_gep(val_ptr, 1)
|
121
|
+
load(len_ptr)
|
122
|
+
end
|
123
|
+
|
124
|
+
def alen(ary)
|
125
|
+
val_ptr = int_to_ptr(ary, P_RARRAY)
|
126
|
+
len_ptr = struct_gep(val_ptr, 1)
|
127
|
+
load(len_ptr)
|
128
|
+
end
|
129
|
+
|
130
|
+
def aref(ary, idx)
|
131
|
+
val_ptr = int_to_ptr(ary, P_RARRAY)
|
132
|
+
data_ptr = struct_gep(val_ptr, 3)
|
133
|
+
data_ptr = load(data_ptr)
|
134
|
+
slot_n = gep(data_ptr, idx.llvm)
|
135
|
+
load(slot_n)
|
136
|
+
end
|
137
|
+
|
138
|
+
def aset(ary, idx, set)
|
139
|
+
val_ptr = int_to_ptr(ary, P_RARRAY)
|
140
|
+
data_ptr = struct_gep(val_ptr, 3)
|
141
|
+
data_ptr = load(data_ptr)
|
142
|
+
slot_n = gep(data_ptr, idx.llvm)
|
143
|
+
store(set, slot_n)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
data/lib/ruby_vm.rb
ADDED
@@ -0,0 +1,352 @@
|
|
1
|
+
require 'llvm'
|
2
|
+
include LLVM
|
3
|
+
include RubyInternals
|
4
|
+
|
5
|
+
class Symbol
|
6
|
+
# turn a symbol object_id into a VALUE
|
7
|
+
# from gc.c, symbols object_id's are calculated like this:
|
8
|
+
# SYM2ID(x) = RSHIFT((unsigned long)x,8)
|
9
|
+
# object_id = (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG;
|
10
|
+
def llvm
|
11
|
+
(((object_id/20) << 8) | 0xe).llvm(MACHINE_WORD)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Object
|
16
|
+
def llvm
|
17
|
+
LLVM::Value.get_immediate_constant(self)
|
18
|
+
end
|
19
|
+
|
20
|
+
def llvm_send(f)
|
21
|
+
# for now, pass the receiver as the first argument
|
22
|
+
ExecutionEngine.runFunction(f, self)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Builder
|
27
|
+
include RubyHelpers
|
28
|
+
|
29
|
+
def self.set_globals(b)
|
30
|
+
@@stack = b.alloca(VALUE, 100)
|
31
|
+
@@stack_ptr = b.alloca(P_VALUE, 0)
|
32
|
+
b.store(@@stack, @@stack_ptr)
|
33
|
+
@@locals = b.alloca(VALUE, 100)
|
34
|
+
end
|
35
|
+
|
36
|
+
def stack
|
37
|
+
@@stack
|
38
|
+
end
|
39
|
+
|
40
|
+
def stack_ptr
|
41
|
+
@@stack_ptr
|
42
|
+
end
|
43
|
+
|
44
|
+
def push(val)
|
45
|
+
sp = load(stack_ptr)
|
46
|
+
store(val, sp)
|
47
|
+
new_sp = gep(sp, 1.llvm)
|
48
|
+
store(new_sp, stack_ptr)
|
49
|
+
end
|
50
|
+
|
51
|
+
def pop
|
52
|
+
sp = load(stack_ptr)
|
53
|
+
new_sp = gep(sp, -1.llvm)
|
54
|
+
store(new_sp, stack_ptr)
|
55
|
+
load(new_sp)
|
56
|
+
end
|
57
|
+
|
58
|
+
def peek(n = 1)
|
59
|
+
sp = load(stack_ptr)
|
60
|
+
peek_sp = gep(sp, (-n).llvm)
|
61
|
+
load(peek_sp)
|
62
|
+
end
|
63
|
+
|
64
|
+
def topn(n)
|
65
|
+
sp = load(stack_ptr)
|
66
|
+
idx = sub((-1).llvm(Type::Int32Ty), n)
|
67
|
+
top_sp = gep(sp, idx)
|
68
|
+
load(top_sp)
|
69
|
+
end
|
70
|
+
|
71
|
+
def locals
|
72
|
+
@@locals
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class OpCodeBuilder
|
77
|
+
def initialize(mod, func, rb_funcs)
|
78
|
+
@mod = mod
|
79
|
+
@func = func
|
80
|
+
@rb_funcs = rb_funcs
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_self
|
84
|
+
@func.arguments.first
|
85
|
+
end
|
86
|
+
|
87
|
+
def nop(b, oprnd)
|
88
|
+
end
|
89
|
+
|
90
|
+
def putnil(b, oprnd)
|
91
|
+
b.push(nil.immediate)
|
92
|
+
end
|
93
|
+
|
94
|
+
def putself(b, oprnd)
|
95
|
+
b.push(get_self)
|
96
|
+
end
|
97
|
+
|
98
|
+
def putobject(b, oprnd)
|
99
|
+
b.push(oprnd.llvm)
|
100
|
+
end
|
101
|
+
|
102
|
+
def pop(b, oprnd)
|
103
|
+
b.pop
|
104
|
+
end
|
105
|
+
|
106
|
+
def dup(b, oprnd)
|
107
|
+
b.push(b.peek)
|
108
|
+
end
|
109
|
+
|
110
|
+
def swap(b, oprn)
|
111
|
+
v1 = b.pop
|
112
|
+
v2 = b.pop
|
113
|
+
b.push(v1)
|
114
|
+
b.push(v2)
|
115
|
+
end
|
116
|
+
|
117
|
+
def setlocal(b, oprnd)
|
118
|
+
v = b.pop
|
119
|
+
local_slot = b.gep(b.locals, oprnd.llvm)
|
120
|
+
b.store(v, local_slot)
|
121
|
+
end
|
122
|
+
|
123
|
+
def getlocal(b, oprnd)
|
124
|
+
local_slot = b.gep(b.locals, oprnd.llvm)
|
125
|
+
val = b.load(local_slot)
|
126
|
+
b.push(val)
|
127
|
+
end
|
128
|
+
|
129
|
+
def opt_plus(b, oprnd)
|
130
|
+
v1 = b.fix2int(b.pop)
|
131
|
+
v2 = b.fix2int(b.pop)
|
132
|
+
sum = b.add(v1, v2)
|
133
|
+
b.push(b.num2fix(sum))
|
134
|
+
end
|
135
|
+
|
136
|
+
def opt_minus(b, oprnd)
|
137
|
+
v1 = b.fix2int(b.pop)
|
138
|
+
v2 = b.fix2int(b.pop)
|
139
|
+
sum = b.sub(v2, v1)
|
140
|
+
b.push(b.num2fix(sum))
|
141
|
+
end
|
142
|
+
|
143
|
+
def opt_mult(b, oprnd)
|
144
|
+
v1 = b.fix2int(b.pop)
|
145
|
+
v2 = b.fix2int(b.pop)
|
146
|
+
mul = b.mul(v1, v2)
|
147
|
+
b.push(b.num2fix(mul))
|
148
|
+
end
|
149
|
+
|
150
|
+
def opt_aref(b, oprnd)
|
151
|
+
idx = b.fix2int(b.pop)
|
152
|
+
ary = b.pop
|
153
|
+
out = b.aref(ary, idx)
|
154
|
+
b.push(out)
|
155
|
+
end
|
156
|
+
|
157
|
+
def opt_aset(b, oprnd)
|
158
|
+
set = b.pop
|
159
|
+
idx = b.fix2int(b.pop)
|
160
|
+
ary = b.pop
|
161
|
+
b.call(@rb_funcs[:rb_ary_store], ary, idx, set)
|
162
|
+
b.push(set)
|
163
|
+
end
|
164
|
+
|
165
|
+
def opt_length(b, oprnd)
|
166
|
+
recv = b.pop
|
167
|
+
len = b.alen(recv)
|
168
|
+
len = b.num2fix(len)
|
169
|
+
b.push(len)
|
170
|
+
end
|
171
|
+
|
172
|
+
def opt_lt(b, oprnd)
|
173
|
+
obj = b.pop
|
174
|
+
recv = b.pop
|
175
|
+
x = b.fix2int(recv)
|
176
|
+
y = b.fix2int(obj)
|
177
|
+
val = b.icmp_slt(x, y)
|
178
|
+
val = b.int_cast(val, LONG, false)
|
179
|
+
val = b.mul(val, 2.llvm)
|
180
|
+
b.push(val)
|
181
|
+
end
|
182
|
+
|
183
|
+
def opt_gt(b, oprnd)
|
184
|
+
obj = b.pop
|
185
|
+
recv = b.pop
|
186
|
+
x = b.fix2int(recv)
|
187
|
+
y = b.fix2int(obj)
|
188
|
+
val = b.icmp_sgt(x, y)
|
189
|
+
val = b.int_cast(val, LONG, false)
|
190
|
+
val = b.mul(val, 2.llvm)
|
191
|
+
b.push(val)
|
192
|
+
end
|
193
|
+
|
194
|
+
def opt_ge(b, oprnd)
|
195
|
+
obj = b.pop
|
196
|
+
recv = b.pop
|
197
|
+
x = b.fix2int(recv)
|
198
|
+
y = b.fix2int(obj)
|
199
|
+
val = b.icmp_sge(x, y)
|
200
|
+
val = b.int_cast(val, LONG, false)
|
201
|
+
val = b.mul(val, 2.llvm)
|
202
|
+
b.push(val)
|
203
|
+
end
|
204
|
+
|
205
|
+
def getinstancevariable(b, oprnd)
|
206
|
+
id = b.call(@rb_funcs[:rb_to_id], oprnd.llvm)
|
207
|
+
v = b.call(@rb_funcs[:rb_ivar_get], get_self, id)
|
208
|
+
b.push(v)
|
209
|
+
end
|
210
|
+
|
211
|
+
def setinstancevariable(b, oprnd)
|
212
|
+
new_val = b.peek
|
213
|
+
id = b.call(@rb_funcs[:rb_to_id], oprnd.llvm)
|
214
|
+
b.call(@rb_funcs[:rb_ivar_set], get_self, id, new_val)
|
215
|
+
end
|
216
|
+
|
217
|
+
def newarray(b, oprnd)
|
218
|
+
ary = b.call(@rb_funcs[:rb_ary_new])
|
219
|
+
b.push(ary)
|
220
|
+
end
|
221
|
+
|
222
|
+
def newhash(b, oprnd)
|
223
|
+
hash = b.call(@rb_funcs[:rb_hash_new])
|
224
|
+
i = oprnd.llvm(Type::Int32Ty) # This is an integer not a fixnum
|
225
|
+
|
226
|
+
entry_block = @func.create_block
|
227
|
+
loop_block = @func.create_block
|
228
|
+
exit_block = @func.create_block
|
229
|
+
|
230
|
+
b.br(entry_block)
|
231
|
+
b.set_insert_point(entry_block)
|
232
|
+
cmp = b.icmp_sgt(i, 0.llvm(Type::Int32Ty))
|
233
|
+
b.cond_br(cmp, loop_block, exit_block)
|
234
|
+
|
235
|
+
b.set_insert_point(loop_block)
|
236
|
+
idx = b.phi(Type::Int32Ty)
|
237
|
+
idx.add_incoming(i, entry_block)
|
238
|
+
next_idx = b.sub(idx, 2.llvm(Type::Int32Ty))
|
239
|
+
idx.add_incoming(next_idx, loop_block)
|
240
|
+
|
241
|
+
n_1 = b.sub(idx, 1.llvm(Type::Int32Ty))
|
242
|
+
n_2 = b.sub(idx, 2.llvm(Type::Int32Ty))
|
243
|
+
b.call(@rb_funcs[:rb_hash_aset], hash, b.topn(n_1), b.topn(n_2))
|
244
|
+
|
245
|
+
cmp = b.icmp_sgt(next_idx, 0.llvm(Type::Int32Ty))
|
246
|
+
b.cond_br(cmp, loop_block, exit_block)
|
247
|
+
|
248
|
+
b.set_insert_point(exit_block)
|
249
|
+
b.push(hash)
|
250
|
+
end
|
251
|
+
|
252
|
+
def send(b, oprnd)
|
253
|
+
recv = nil.immediate
|
254
|
+
id = b.call(@rb_funcs[:rb_to_id], :inspect.immediate)
|
255
|
+
argc = 0.llvm(Type::Int32Ty)
|
256
|
+
val = b.call(@rb_funcs[:rb_funcall2], recv, id, argc, b.stack)
|
257
|
+
b.push(val)
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
class RubyVM
|
262
|
+
def self.start
|
263
|
+
@module = LLVM::Module.new('ruby_vm')
|
264
|
+
ExecutionEngine.get(@module)
|
265
|
+
|
266
|
+
@rb_ary_new = @module.external_function('rb_ary_new', ftype(VALUE, []))
|
267
|
+
@rb_hash_new = @module.external_function('rb_hash_new', ftype(VALUE, []))
|
268
|
+
@rb_hash_aset = @module.external_function('rb_hash_aset', ftype(VALUE, [VALUE, VALUE, VALUE]))
|
269
|
+
@rb_ary_store = @module.external_function('rb_ary_store', ftype(VALUE, [VALUE, LONG, VALUE]))
|
270
|
+
@rb_to_id = @module.external_function('rb_to_id', ftype(VALUE, [VALUE]))
|
271
|
+
@rb_ivar_get = @module.external_function('rb_ivar_get', ftype(VALUE, [VALUE, ID]))
|
272
|
+
@rb_ivar_set = @module.external_function('rb_ivar_set', ftype(VALUE, [VALUE, ID, VALUE]))
|
273
|
+
@rb_funcall2 = @module.external_function('rb_funcall2', ftype(VALUE, [VALUE, ID, INT, P_VALUE]))
|
274
|
+
|
275
|
+
@rb_funcs = {
|
276
|
+
:rb_ary_new => @rb_ary_new,
|
277
|
+
:rb_hash_new => @rb_hash_new,
|
278
|
+
:rb_hash_aset => @rb_hash_aset,
|
279
|
+
:rb_ary_store => @rb_ary_store,
|
280
|
+
:rb_to_id => @rb_to_id,
|
281
|
+
:rb_ivar_get => @rb_ivar_get,
|
282
|
+
:rb_ivar_set => @rb_ivar_set,
|
283
|
+
:rb_funcall2 => @rb_funcall2
|
284
|
+
}
|
285
|
+
|
286
|
+
@func_n = 0
|
287
|
+
end
|
288
|
+
|
289
|
+
def self.ftype(ret, args)
|
290
|
+
Type.function(ret, args)
|
291
|
+
end
|
292
|
+
|
293
|
+
def self.call_bytecode(bytecode, farg)
|
294
|
+
f = compile_bytecode(bytecode)
|
295
|
+
ExecutionEngine.run_function(f, nil, farg)
|
296
|
+
end
|
297
|
+
|
298
|
+
def self.method_send(recv, compiled_method, farg = nil)
|
299
|
+
ExecutionEngine.run_function(compiled_method, recv, farg)
|
300
|
+
end
|
301
|
+
|
302
|
+
def self.compile_bytecode(bytecode)
|
303
|
+
f = @module.get_or_insert_function("vm_func#{@func_n}", Type.function(VALUE, [VALUE, VALUE]))
|
304
|
+
@func_n += 1
|
305
|
+
|
306
|
+
get_self = f.arguments[0]
|
307
|
+
|
308
|
+
entry_block = f.create_block
|
309
|
+
b = entry_block.builder
|
310
|
+
Builder.set_globals(b)
|
311
|
+
b.push(f.arguments[1])
|
312
|
+
|
313
|
+
blocks = bytecode.map { f.create_block }
|
314
|
+
exit_block = f.create_block
|
315
|
+
blocks << exit_block
|
316
|
+
b.br(blocks.first)
|
317
|
+
|
318
|
+
op_builder = OpCodeBuilder.new(@module, f, @rb_funcs)
|
319
|
+
|
320
|
+
bytecode.each_with_index do |opcode, i|
|
321
|
+
op, arg = opcode
|
322
|
+
|
323
|
+
block = blocks[i]
|
324
|
+
b.set_insert_point(block)
|
325
|
+
|
326
|
+
case op
|
327
|
+
when :jump
|
328
|
+
b.br(blocks[arg])
|
329
|
+
when :branchif
|
330
|
+
v = b.pop
|
331
|
+
cmp = b.icmp_eq(v, 0.llvm)
|
332
|
+
b.cond_br(cmp, blocks[i+1], blocks[arg])
|
333
|
+
when :branchunless
|
334
|
+
v = b.pop
|
335
|
+
cmp = b.icmp_eq(v, 0.llvm)
|
336
|
+
b.cond_br(cmp, blocks[arg], blocks[i+1])
|
337
|
+
else
|
338
|
+
op_builder.__send__(op, b, arg)
|
339
|
+
end
|
340
|
+
|
341
|
+
if op != :jump && op != :branchif && op != :branchunless
|
342
|
+
b.br(blocks[i+1])
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
b = exit_block.builder
|
347
|
+
ret_val = b.pop
|
348
|
+
b.return(ret_val)
|
349
|
+
|
350
|
+
f
|
351
|
+
end
|
352
|
+
end
|