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