ruby-libjit 0.1.0
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 +6 -0
- data/LGPL +515 -0
- data/LICENSE +20 -0
- data/README +50 -0
- data/ext/extconf.rb +100 -0
- data/ext/insns.inc.rpp +204 -0
- data/ext/jit.c +1521 -0
- data/ext/method_data.c +385 -0
- data/ext/method_data.c.rpp +294 -0
- data/ext/method_data.h +11 -0
- data/ext/minimal_node.c +35 -0
- data/ext/minimal_node.h +52 -0
- data/ext/rubyjit.h +20 -0
- data/ext/rubypp.rb +97 -0
- data/lib/jit/array.rb +135 -0
- data/lib/jit/function.rb +201 -0
- data/lib/jit/struct.rb +163 -0
- data/lib/jit/value.rb +199 -0
- data/lib/jit.rb +5 -0
- data/sample/fib.rb +29 -0
- data/sample/gcd_benchmark.rb +117 -0
- data/sample/simple.rb +15 -0
- data/test/test_jit_array.rb +70 -0
- data/test/test_jit_function.rb +329 -0
- data/test/test_jit_struct.rb +111 -0
- data/test/test_jit_value.rb +258 -0
- metadata +77 -0
data/ext/minimal_node.h
ADDED
@@ -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
|
+
|
data/lib/jit/function.rb
ADDED
@@ -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
|
+
|