ruby-libjit 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,52 @@
1
+ #ifndef minimal_node_h
2
+ #define minimal_node_h
3
+
4
+ #ifdef NEED_MINIMAL_NODE
5
+
6
+ #include "ruby.h"
7
+
8
+ typedef struct RNode {
9
+ unsigned long flags;
10
+ void * reserved;
11
+ union {
12
+ struct RNode * node;
13
+ VALUE (*cfunc)(ANYARGS);
14
+ } u1;
15
+ union {
16
+ struct RNode * node;
17
+ VALUE value;
18
+ } u2;
19
+ union {
20
+ struct RNode * node;
21
+ } u3;
22
+ } NODE;
23
+
24
+ #define nd_cfnc u1.cfunc
25
+ #define nd_rval u2.value
26
+
27
+ #define NEW_NODE(t,a0,a1,a2) rb_node_newnode((t),(VALUE)(a0),(VALUE)(a1),(VALUE)(a2))
28
+
29
+ /* TODO: No way to know the correct size of node_type */
30
+ enum node_type {
31
+ NODE_FOO,
32
+ };
33
+
34
+ void rb_add_method(VALUE, ID, NODE *, int);
35
+ NODE *rb_node_newnode(enum node_type, VALUE, VALUE, VALUE);
36
+
37
+ extern int NODE_MEMO;
38
+ extern int NODE_METHOD;
39
+ extern int NODE_FBODY;
40
+ extern int NODE_CFUNC;
41
+
42
+ void Init_minimal_node();
43
+
44
+ #define NOEX_PUBLIC 0x0
45
+
46
+ #define NEW_METHOD(n,x,v) NEW_NODE(NODE_METHOD,x,n,v)
47
+ #define NEW_FBODY(n,i) NEW_NODE(NODE_FBODY,i,n,0)
48
+ #define NEW_CFUNC(f,c) NEW_NODE(NODE_CFUNC,f,c,0)
49
+
50
+ #endif
51
+
52
+ #endif
data/ext/rubyjit.h ADDED
@@ -0,0 +1,20 @@
1
+ #ifndef RUBYJIT_H
2
+ #define RUBYJIT_H
3
+
4
+ enum Ruby_Libjit_Tag
5
+ {
6
+ RJT_OBJECT,
7
+ RJT_ID,
8
+ RJT_FUNCTION_PTR,
9
+ RJT_RUBY_VARARG_SIGNATURE,
10
+ RJT_VALUE_OBJECTS,
11
+ RJT_FUNCTIONS,
12
+ RJT_CONTEXT,
13
+ RJT_TAG_FOR_SIGNATURE
14
+ };
15
+
16
+ extern jit_type_t jit_type_VALUE;
17
+ extern jit_type_t jit_type_ID;
18
+ extern jit_type_t jit_type_Function_Ptr;
19
+
20
+ #endif
data/ext/rubypp.rb ADDED
@@ -0,0 +1,97 @@
1
+ class Preprocessor
2
+ def initialize(input, output, filename)
3
+ @input = input
4
+ @output = output
5
+ @filename = filename
6
+ @linenum = 1
7
+ end
8
+
9
+ def getline
10
+ line = @input.gets
11
+ @linenum += 1 if not line.nil?
12
+ return line
13
+ end
14
+
15
+ def preprocess
16
+ success = false
17
+ begin
18
+ loop do
19
+ line = getline
20
+ break if line.nil?
21
+ case line
22
+ when /(.*[^\\]|^)\#\{(.*?)\}(.*)/
23
+ puts "#{$1}#{evaluate($2, @linenum)}#{$3}"
24
+ when /^\#ruby\s+<<(.*)/
25
+ marker = $1
26
+ str = ''
27
+ evalstart = @linenum
28
+ loop do
29
+ line = getline
30
+ if line.nil? then
31
+ raise "End of input without #{marker}"
32
+ end
33
+ break if line.chomp == marker
34
+ str << line
35
+ end
36
+ result = evaluate(str, evalstart)
37
+ puts result if not result.nil?
38
+ when /^\#ruby\s+(.*)/
39
+ str = line = $1
40
+ while line[-1] == ?\\
41
+ str.chop!
42
+ line = getline
43
+ break if line.nil?
44
+ line.chomp!
45
+ str << line
46
+ end
47
+ result = evaluate(str, @linenum)
48
+ puts result if not result.nil?
49
+ else
50
+ puts line
51
+ end
52
+ end
53
+ success = true
54
+ ensure
55
+ if not success then
56
+ $stderr.puts "Error on line #{@linenum}:"
57
+ end
58
+ end
59
+ end
60
+
61
+ def evaluate(str, linenum)
62
+ result = eval(str, TOPLEVEL_BINDING, @filename, linenum)
63
+ success = true
64
+ return result
65
+ end
66
+
67
+ def puts(line='')
68
+ @output.puts(line)
69
+ end
70
+ end
71
+
72
+ def puts(line='')
73
+ $preprocessor.puts(line)
74
+ end
75
+
76
+ def rubypp(input_file, output_file)
77
+ input = input_file ? File.open(input_file) : $stdin
78
+ output = output_file ? File.open(output_file, 'w') : $stdout
79
+
80
+ success = false
81
+ begin
82
+ $preprocessor = Preprocessor.new(input, output, input_file || "(stdin)")
83
+ $preprocessor.preprocess()
84
+ success = true
85
+ ensure
86
+ if not success then
87
+ File.unlink(output_file) rescue Errno::ENOENT
88
+ end
89
+ end
90
+ end
91
+
92
+ if __FILE__ == $0 then
93
+ input_file = ARGV[0]
94
+ output_file = ARGV[1]
95
+ rubypp(input_file, output_file)
96
+ end
97
+
data/lib/jit/array.rb ADDED
@@ -0,0 +1,135 @@
1
+ require 'jit'
2
+ require 'jit/value'
3
+
4
+ module JIT
5
+
6
+ # An abstraction for a fixed-length array type.
7
+ #
8
+ # Example usage:
9
+ #
10
+ # array_type = JIT::Array.new(JIT::Type::INT, 4)
11
+ #
12
+ # JIT::Context.build do |context|
13
+ # signature = JIT::Type.create_signature(
14
+ # JIT::ABI::CDECL, JIT::Type::INT, [ ])
15
+ #
16
+ # function = JIT::Function.compile(context, signature) do |f|
17
+ # array_instance = array_type.create(f)
18
+ # array_instance[0] = f.const(JIT::Type::INT, 42)
19
+ # f.insn_return(array_instance[0])
20
+ # end
21
+ #
22
+ # end
23
+ #
24
+ class Array < JIT::Type
25
+ attr_reader :type
26
+ attr_reader :length
27
+
28
+ # Create a new JIT array type.
29
+ #
30
+ # +type+:: The type of the elements in the array.
31
+ # +length+:: The number of elements in the array.
32
+ #
33
+ def self.new(type, length)
34
+ array = self.create_struct([ type ] * length)
35
+ array.instance_eval do
36
+ @type = type
37
+ @length = length
38
+ end
39
+ return array
40
+ end
41
+
42
+ # Wrap an existing array.
43
+ #
44
+ # +ptr+:: A pointer to the first element in the array.
45
+ #
46
+ def wrap(ptr)
47
+ return Instance.wrap(self, ptr)
48
+ end
49
+
50
+ # Create a new array.
51
+ #
52
+ # +function+:: The JIT::Function this array will be used in.
53
+ #
54
+ def create(function)
55
+ instance = function.value(self)
56
+ ptr = function.insn_address_of(instance)
57
+ return wrap(ptr)
58
+ end
59
+
60
+ # Return the offset (in bytes) of the element at the given +index+.
61
+ #
62
+ # +index+:: The index of the desired element.
63
+ #
64
+ def offset_of(index)
65
+ return self.get_offset(index)
66
+ end
67
+
68
+ # Return the type of the element at the given +index+.
69
+ #
70
+ # +index+:: The index of the desired element.
71
+ #
72
+ def type_of(index)
73
+ return @type
74
+ end
75
+
76
+ # An abstraction for an instance of a fixed-length array.
77
+ #
78
+ class Instance < JIT::Value
79
+ attr_reader :array_type
80
+ attr_reader :type
81
+ attr_reader :ptr
82
+
83
+ # TODO: This breaks code below?
84
+ # attr_reader :function
85
+
86
+ # Wrap an existing array.
87
+ #
88
+ # +array_type+:: The JIT::Array type to wrap.
89
+ # +ptr+:: A pointer to the first element in the array.
90
+ #
91
+ def self.wrap(array_type, ptr)
92
+ pointer_type = JIT::Type.create_pointer(array_type)
93
+ value = self.new_value(ptr.function, pointer_type)
94
+ value.store(ptr)
95
+ value.instance_eval do
96
+ @array_type = array_type
97
+ @type = array_type.type
98
+ @function = ptr.function
99
+ @ptr = ptr
100
+ end
101
+ return value
102
+ end
103
+
104
+ # Generate JIT code to retrieve the element at the given +index+.
105
+ #
106
+ # +index+:: The index of the desired element. The value of the
107
+ # index must be known at compile-time.
108
+ #
109
+ def [](index)
110
+ @function.insn_load_relative(
111
+ @ptr,
112
+ @array_type.offset_of(index),
113
+ @array_type.type_of(index))
114
+ end
115
+
116
+ # Generate JIT code to assign to the element at the given +index+.
117
+ #
118
+ # +index+:: The index of the desired element. The value of the
119
+ # index must be known at compile-time.
120
+ # +value+:: The JIT::Value to assign to the element.
121
+ #
122
+ def []=(index, value)
123
+ @function.insn_store_relative(
124
+ @ptr,
125
+ @array_type.offset_of(index),
126
+ value)
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ if __FILE__ == $0 then
133
+ a = JIT::Array.new()
134
+ end
135
+
@@ -0,0 +1,201 @@
1
+ require 'jit'
2
+
3
+ module JIT
4
+ class Function
5
+ # An abstraction for conditionals.
6
+ #
7
+ # Example usage:
8
+ #
9
+ # function.if(condition) {
10
+ # # condition is true
11
+ # } .elsif(condition2) {
12
+ # # condition2 is true
13
+ # } .else {
14
+ # # condition1 and condition2 are false
15
+ # } .end
16
+ #
17
+ # Caution: if you omit end, then the generated code will have
18
+ # undefined behavior, but there will be no warning generated.
19
+ def if(cond, end_label = Label.new, &block)
20
+ false_label = Label.new
21
+ insn_branch_if_not(cond, false_label)
22
+ block.call
23
+ insn_branch(end_label)
24
+ insn_label(false_label)
25
+ return If.new(self, end_label)
26
+ end
27
+
28
+ # An abstraction for an inverted conditional.
29
+ #
30
+ # Example usage:
31
+ #
32
+ # function.unless(condition) {
33
+ # # condition is false
34
+ # } .elsunless(condition2) {
35
+ # # condition2 is false
36
+ # } .else {
37
+ # # condition1 and condition2 are true
38
+ # } .end
39
+ #
40
+ # Caution: if you omit end, then the generated code will have
41
+ # undefined behavior, but there will be no warning generated.
42
+ def unless(cond, end_label = Label.new, &block)
43
+ true_label = Label.new
44
+ insn_branch_if(cond, true_label)
45
+ block.call
46
+ insn_branch(end_label)
47
+ insn_label(true_label)
48
+ return If.new(self, end_label)
49
+ end
50
+
51
+ # :nodoc:
52
+ class If
53
+ def initialize(function, end_label)
54
+ @function = function
55
+ @end_label = end_label
56
+ end
57
+
58
+ def else(&block)
59
+ block.call
60
+ return self
61
+ end
62
+
63
+ def elsif(cond, &block)
64
+ return @function.if(cond, @end_label, &block)
65
+ end
66
+
67
+ def elsunless(cond, &block)
68
+ return @function.unless(cond, @end_label, &block)
69
+ end
70
+
71
+ def end
72
+ @function.insn_label(@end_label)
73
+ end
74
+ end
75
+
76
+ # An abstraction for a multi-way conditional.
77
+ #
78
+ # Example usage:
79
+ #
80
+ # function.case(value1)
81
+ # .when(value2) {
82
+ # # value1 == value2
83
+ # }.when(value3) {
84
+ # # value1 == value3
85
+ # } .else {
86
+ # # all other cases fell through
87
+ # } .end
88
+ #
89
+ # Caution: if you omit end, then the generated code will have
90
+ # undefined behavior, but there will be no warning generated.
91
+ def case(value)
92
+ return Case.new(self, value)
93
+ end
94
+
95
+ # :nodoc:
96
+ class Case
97
+ def initialize(function, value)
98
+ @function = function
99
+ @value = value
100
+ @if = nil
101
+ end
102
+
103
+ def when(value, &block)
104
+ if not @if then
105
+ @if = @function.if(value == @value, &block)
106
+ else
107
+ @if.elsif(value == @value, &block)
108
+ end
109
+ return self
110
+ end
111
+
112
+ def else(&block)
113
+ @if.else(&block)
114
+ end
115
+
116
+ def end
117
+ @if.end if @if
118
+ end
119
+ end
120
+
121
+ # Usage:
122
+ #
123
+ # until(proc { <condition> }) {
124
+ # # loop body
125
+ # } .end
126
+ #
127
+ def until(cond, &block)
128
+ start_label = Label.new
129
+ done_label = Label.new
130
+ insn_label(start_label)
131
+ insn_branch_if(cond.call, done_label)
132
+ loop = Loop.new(self, start_label, done_label)
133
+ block.call(loop)
134
+ insn_branch(start_label)
135
+ insn_label(done_label)
136
+ return loop
137
+ end
138
+
139
+ # Usage:
140
+ #
141
+ # while(proc { <condition> }) {
142
+ # # loop body
143
+ # } .end
144
+ #
145
+ def while(cond, &block)
146
+ start_label = Label.new
147
+ done_label = Label.new
148
+ insn_label(start_label)
149
+ insn_branch_if_not(cond.call, done_label)
150
+ loop = Loop.new(self, start_label, done_label)
151
+ block.call(loop)
152
+ insn_branch(start_label)
153
+ insn_label(done_label)
154
+ return loop
155
+ end
156
+
157
+ # :nodoc:
158
+ class Loop
159
+ def initialize(function, start_label, done_label)
160
+ @function = function
161
+ @redo_label = start_label
162
+ @done_label = done_label
163
+ end
164
+
165
+ def end
166
+ end
167
+
168
+ def break
169
+ @function.insn_branch(@done_label)
170
+ end
171
+
172
+ def redo
173
+ @function.insn_branch(@redo_label)
174
+ end
175
+
176
+ def redo_from_here
177
+ @redo_label = JIT::Label.new
178
+ @function.insn_label(@redo_label)
179
+ end
180
+ end
181
+
182
+ # An alias for get_param
183
+ def param(n)
184
+ self.get_param(n)
185
+ end
186
+
187
+ # An alias for insn_return
188
+ def return(result)
189
+ self.insn_return(result)
190
+ end
191
+
192
+ # Create a JIT::Context and compile a new function within that
193
+ # context.
194
+ def self.build(*args, &block)
195
+ JIT::Context.build do |context|
196
+ JIT::Function.compile(context, *args, &block)
197
+ end
198
+ end
199
+ end
200
+ end
201
+
data/lib/jit/struct.rb ADDED
@@ -0,0 +1,163 @@
1
+ require 'jit'
2
+
3
+ module JIT
4
+
5
+ # An abstraction for a record composed of heterogenous fields.
6
+ #
7
+ # Example usage:
8
+ #
9
+ # point_type = JIT::Struct.new(
10
+ # [ :x, JIT::Type::INT ],
11
+ # [ :y, JIT::Type::INT ],
12
+ # [ :z, JIT::Type::INT ])
13
+ #
14
+ # JIT::Context.build do |context|
15
+ # signature = JIT::Type.create_signature(
16
+ # JIT::ABI::CDECL, JIT::Type::INT, [ ])
17
+ #
18
+ # function = JIT::Function.compile(context, signature) do |f|
19
+ # point = point_type.create(f)
20
+ # point.x = function.const(JIT::Type::INT, 1)
21
+ # point.y = function.const(JIT::Type::INT, 2)
22
+ # point.z = function.const(JIT::Type::INT, 3)
23
+ # f.insn_return(point.x)
24
+ # end
25
+ #
26
+ # end
27
+ #
28
+ class Struct < JIT::Type
29
+
30
+ # Construct a new JIT structure type.
31
+ #
32
+ # +members+:: A list of members, where each element in the list is a
33
+ # two-element array [ :name, type ]
34
+ #
35
+ def self.new(*members)
36
+ member_names = members.map { |m| m[0].to_s.intern }
37
+ member_types = members.map { |m| m[1] }
38
+ type = self.create_struct(member_types)
39
+ type.instance_eval do
40
+ @members = members
41
+ @member_names = member_names
42
+ @member_types = member_types
43
+ @index = Hash[*@member_names.zip((0..@member_names.size).to_a).flatten]
44
+ end
45
+ return type
46
+ end
47
+
48
+ # Return the names of the members in the structure.
49
+ def members
50
+ return @member_names
51
+ end
52
+
53
+ # Wrap an existing structure.
54
+ #
55
+ # +ptr+:: A pointer to the first element in the structure.
56
+ #
57
+ def wrap(ptr)
58
+ return Instance.new(self, ptr)
59
+ end
60
+
61
+ # Create a new structure.
62
+ #
63
+ # +function+:: The JIT::Function this structure will be used in.
64
+ #
65
+ def create(function)
66
+ instance = function.value(self)
67
+ ptr = function.insn_address_of(instance)
68
+ return wrap(ptr)
69
+ end
70
+
71
+ # Return the offset (in bytes) of the element with the given name.
72
+ #
73
+ # +name+:: The name of the desired element.
74
+ #
75
+ def offset_of(name)
76
+ name = (Symbol === name) ? name : name.to_s.intern
77
+ return self.get_offset(@index[name])
78
+ end
79
+
80
+ # Change the offset of the element with the given name.
81
+ #
82
+ # +name+:: The name of the desired element.
83
+ # +offset+:: The new offset.
84
+ #
85
+ def set_offset_of(name, offset)
86
+ name = (Symbol === name) ? name : name.to_s.intern
87
+ return self.set_offset(@index[name], offset)
88
+ end
89
+
90
+ # Return the type of the element with the given name.
91
+ #
92
+ # +name+:: The name of the desired element.
93
+ #
94
+ def type_of(name)
95
+ name = (Symbol === name) ? name : name.to_s.intern
96
+ return @member_types[@index[name]]
97
+ end
98
+
99
+ # An abstraction for an instance of a JIT::Struct.
100
+ #
101
+ class Instance
102
+ attr_reader :ptr
103
+
104
+ # Wrap an existing structure.
105
+ #
106
+ # +struct+:: The JIT::Struct type to wrap.
107
+ # +ptr+ A pointer to the first element of the structure.
108
+ #
109
+ def initialize(struct, ptr)
110
+ @struct = struct
111
+ @function = ptr.function
112
+ @ptr = ptr
113
+
114
+ mod = Module.new do
115
+ struct.members.each do |name|
116
+ define_method("#{name}") do
117
+ self[name] # return
118
+ end
119
+
120
+ define_method("#{name}=") do |value|
121
+ self[name] = value # return
122
+ end
123
+ end
124
+ end
125
+
126
+ extend(mod)
127
+ end
128
+
129
+ # Generate JIT code to retrieve the element with the given name.
130
+ #
131
+ # +name+:: The name of the desired element.
132
+ #
133
+ def [](name)
134
+ @function.insn_load_relative(
135
+ @ptr,
136
+ @struct.offset_of(name),
137
+ @struct.type_of(name))
138
+ end
139
+
140
+ # Generate JIT code to assign to the element with the given name.
141
+ #
142
+ # +name+:: The name of the desired element.
143
+ # +value+:: The JIT::Value to assign to the element.
144
+ #
145
+ def []=(name, value)
146
+ @function.insn_store_relative(
147
+ @ptr,
148
+ @struct.offset_of(name),
149
+ value)
150
+ end
151
+
152
+ def members
153
+ return @struct.members
154
+ end
155
+ end
156
+ end
157
+ end
158
+
159
+ if __FILE__ == $0 then
160
+ s = JIT::Struct.new()
161
+ p s
162
+ end
163
+