ytljit 0.0.1
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/README +29 -0
- data/Rakefile +22 -0
- data/ext/code_alloc.c +266 -0
- data/ext/extconf.rb +3 -0
- data/ext/ytljit.c +527 -0
- data/ext/ytljit.h +285 -0
- data/lib/ytljit/asm.rb +205 -0
- data/lib/ytljit/asmext.rb +199 -0
- data/lib/ytljit/asmext_x64.rb +212 -0
- data/lib/ytljit/asmext_x86.rb +128 -0
- data/lib/ytljit/asmutil.rb +182 -0
- data/lib/ytljit/codespace.rb +92 -0
- data/lib/ytljit/error.rb +7 -0
- data/lib/ytljit/instruction.rb +138 -0
- data/lib/ytljit/instruction_ia.rb +1298 -0
- data/lib/ytljit/instruction_x64.rb +41 -0
- data/lib/ytljit/instruction_x86.rb +11 -0
- data/lib/ytljit/marshal.rb +133 -0
- data/lib/ytljit/matcher.rb +235 -0
- data/lib/ytljit/rubyvm.rb +63 -0
- data/lib/ytljit/struct.rb +125 -0
- data/lib/ytljit/type.rb +112 -0
- data/lib/ytljit/util.rb +63 -0
- data/lib/ytljit/vm.rb +1649 -0
- data/lib/ytljit/vm_codegen.rb +491 -0
- data/lib/ytljit/vm_inline_method.rb +85 -0
- data/lib/ytljit/vm_inspect.rb +74 -0
- data/lib/ytljit/vm_sendnode.rb +561 -0
- data/lib/ytljit/vm_trans.rb +508 -0
- data/lib/ytljit/vm_type.rb +299 -0
- data/lib/ytljit/vm_type_gen.rb +158 -0
- data/lib/ytljit/vm_typeinf.rb +98 -0
- data/lib/ytljit.rb +46 -0
- data/test/asmsample.rb +117 -0
- data/test/cstest.rb +61 -0
- data/test/marshaltest.rb +27 -0
- data/test/test_assemble.rb +148 -0
- data/test/test_assemble2.rb +286 -0
- data/test/test_codespace.rb +102 -0
- data/test/test_typeinf.rb +21 -0
- data/test/tivmtest.rb +54 -0
- data/test/vmtest.rb +59 -0
- data/test/vmtest2.rb +41 -0
- data/test/vmtest3.rb +22 -0
- data/test/vmtest_compile_only.rb +41 -0
- data/test/vmtest_execute_only.rb +22 -0
- metadata +121 -0
data/ext/ytljit.h
ADDED
@@ -0,0 +1,285 @@
|
|
1
|
+
#define MAX_DL_HANDLES 10
|
2
|
+
#define INIT_CODE_SPACE_SIZE 64
|
3
|
+
#define VALUE_SPACE_SIZE (8 * 1024)
|
4
|
+
|
5
|
+
#define OPEN_CHECK(COND) \
|
6
|
+
do { \
|
7
|
+
if ((COND) == NULL) { \
|
8
|
+
printf("Open failed %d handle", used_dl_handles); \
|
9
|
+
} \
|
10
|
+
} while(0)
|
11
|
+
|
12
|
+
struct CodeSpace {
|
13
|
+
size_t size;
|
14
|
+
size_t used;
|
15
|
+
char body[1];
|
16
|
+
};
|
17
|
+
|
18
|
+
VALUE ytl_address_of(VALUE, VALUE);
|
19
|
+
VALUE ytl_code_space_allocate(VALUE);
|
20
|
+
|
21
|
+
void init_csarena();
|
22
|
+
void *csalloc(int);
|
23
|
+
void csfree(void *);
|
24
|
+
|
25
|
+
extern VALUE ytl_mYTLJit;
|
26
|
+
extern VALUE ytl_cCodeSpace;
|
27
|
+
extern VALUE ytl_cValueSpace;
|
28
|
+
extern VALUE ytl_cStepHandler;
|
29
|
+
extern VALUE ytl_eStepHandler;
|
30
|
+
|
31
|
+
/* Copy from node.h */
|
32
|
+
typedef struct RNode {
|
33
|
+
unsigned long flags;
|
34
|
+
char *nd_file;
|
35
|
+
union {
|
36
|
+
struct RNode *node;
|
37
|
+
ID id;
|
38
|
+
VALUE value;
|
39
|
+
VALUE (*cfunc)(ANYARGS);
|
40
|
+
ID *tbl;
|
41
|
+
} u1;
|
42
|
+
union {
|
43
|
+
struct RNode *node;
|
44
|
+
ID id;
|
45
|
+
long argc;
|
46
|
+
VALUE value;
|
47
|
+
} u2;
|
48
|
+
union {
|
49
|
+
struct RNode *node;
|
50
|
+
ID id;
|
51
|
+
long state;
|
52
|
+
struct rb_global_entry *entry;
|
53
|
+
long cnt;
|
54
|
+
VALUE value;
|
55
|
+
} u3;
|
56
|
+
} NODE;
|
57
|
+
|
58
|
+
|
59
|
+
/* Copy from vm_core.h */
|
60
|
+
|
61
|
+
struct rb_iseq_struct {
|
62
|
+
/***************/
|
63
|
+
/* static data */
|
64
|
+
/***************/
|
65
|
+
|
66
|
+
VALUE type; /* instruction sequence type */
|
67
|
+
VALUE name; /* String: iseq name */
|
68
|
+
VALUE filename; /* file information where this sequence from */
|
69
|
+
VALUE filepath; /* real file path or nil */
|
70
|
+
VALUE *iseq; /* iseq (insn number and openrads) */
|
71
|
+
VALUE *iseq_encoded; /* encoded iseq */
|
72
|
+
unsigned long iseq_size;
|
73
|
+
VALUE mark_ary; /* Array: includes operands which should be GC marked */
|
74
|
+
VALUE coverage; /* coverage array */
|
75
|
+
unsigned short line_no;
|
76
|
+
|
77
|
+
/* insn info, must be freed */
|
78
|
+
struct iseq_insn_info_entry *insn_info_table;
|
79
|
+
size_t insn_info_size;
|
80
|
+
|
81
|
+
ID *local_table; /* must free */
|
82
|
+
int local_table_size;
|
83
|
+
|
84
|
+
/* method, class frame: sizeof(vars) + 1, block frame: sizeof(vars) */
|
85
|
+
int local_size;
|
86
|
+
|
87
|
+
struct iseq_inline_cache_entry *ic_entries;
|
88
|
+
int ic_size;
|
89
|
+
|
90
|
+
/**
|
91
|
+
* argument information
|
92
|
+
*
|
93
|
+
* def m(a1, a2, ..., aM, # mandatory
|
94
|
+
* b1=(...), b2=(...), ..., bN=(...), # optinal
|
95
|
+
* *c, # rest
|
96
|
+
* d1, d2, ..., dO, # post
|
97
|
+
* &e) # block
|
98
|
+
* =>
|
99
|
+
*
|
100
|
+
* argc = M
|
101
|
+
* arg_rest = M+N+1 // or -1 if no rest arg
|
102
|
+
* arg_opts = N
|
103
|
+
* arg_opts_tbl = [ (N entries) ]
|
104
|
+
* arg_post_len = O // 0 if no post arguments
|
105
|
+
* arg_post_start = M+N+2
|
106
|
+
* arg_block = M+N + 1 + O + 1 // -1 if no block arg
|
107
|
+
* arg_simple = 0 if not simple arguments.
|
108
|
+
* = 1 if no opt, rest, post, block.
|
109
|
+
* = 2 if ambiguos block parameter ({|a|}).
|
110
|
+
* arg_size = argument size.
|
111
|
+
*/
|
112
|
+
|
113
|
+
int argc;
|
114
|
+
int arg_simple;
|
115
|
+
int arg_rest;
|
116
|
+
int arg_block;
|
117
|
+
int arg_opts;
|
118
|
+
int arg_post_len;
|
119
|
+
int arg_post_start;
|
120
|
+
int arg_size;
|
121
|
+
VALUE *arg_opt_table;
|
122
|
+
|
123
|
+
size_t stack_max; /* for stack overflow check */
|
124
|
+
|
125
|
+
/* catch table */
|
126
|
+
struct iseq_catch_table_entry *catch_table;
|
127
|
+
int catch_table_size;
|
128
|
+
|
129
|
+
/* for child iseq */
|
130
|
+
struct rb_iseq_struct *parent_iseq;
|
131
|
+
struct rb_iseq_struct *local_iseq;
|
132
|
+
|
133
|
+
/****************/
|
134
|
+
/* dynamic data */
|
135
|
+
/****************/
|
136
|
+
|
137
|
+
VALUE self;
|
138
|
+
VALUE orig; /* non-NULL if its data have origin */
|
139
|
+
|
140
|
+
/* block inlining */
|
141
|
+
/*
|
142
|
+
* NODE *node;
|
143
|
+
* void *special_block_builder;
|
144
|
+
* void *cached_special_block_builder;
|
145
|
+
* VALUE cached_special_block;
|
146
|
+
*/
|
147
|
+
|
148
|
+
/* klass/module nest information stack (cref) */
|
149
|
+
NODE *cref_stack;
|
150
|
+
VALUE klass;
|
151
|
+
|
152
|
+
/* misc */
|
153
|
+
ID defined_method_id; /* for define_method */
|
154
|
+
|
155
|
+
/* used at compile time */
|
156
|
+
struct iseq_compile_data *compile_data;
|
157
|
+
};
|
158
|
+
|
159
|
+
/* Copy from method.h */
|
160
|
+
typedef enum {
|
161
|
+
NOEX_PUBLIC = 0x00,
|
162
|
+
NOEX_NOSUPER = 0x01,
|
163
|
+
NOEX_PRIVATE = 0x02,
|
164
|
+
NOEX_PROTECTED = 0x04,
|
165
|
+
NOEX_MASK = 0x06,
|
166
|
+
NOEX_BASIC = 0x08,
|
167
|
+
NOEX_UNDEF = NOEX_NOSUPER,
|
168
|
+
NOEX_MODFUNC = 0x12,
|
169
|
+
NOEX_SUPER = 0x20,
|
170
|
+
NOEX_VCALL = 0x40,
|
171
|
+
NOEX_RESPONDS = 0x80
|
172
|
+
} rb_method_flag_t;
|
173
|
+
|
174
|
+
#define NOEX_SAFE(n) ((int)((n) >> 8) & 0x0F)
|
175
|
+
#define NOEX_WITH(n, s) ((s << 8) | (n) | (ruby_running ? 0 : NOEX_BASIC))
|
176
|
+
#define NOEX_WITH_SAFE(n) NOEX_WITH(n, rb_safe_level())
|
177
|
+
|
178
|
+
/* method data type */
|
179
|
+
|
180
|
+
typedef enum {
|
181
|
+
VM_METHOD_TYPE_ISEQ,
|
182
|
+
VM_METHOD_TYPE_CFUNC,
|
183
|
+
VM_METHOD_TYPE_ATTRSET,
|
184
|
+
VM_METHOD_TYPE_IVAR,
|
185
|
+
VM_METHOD_TYPE_BMETHOD,
|
186
|
+
VM_METHOD_TYPE_ZSUPER,
|
187
|
+
VM_METHOD_TYPE_UNDEF,
|
188
|
+
VM_METHOD_TYPE_NOTIMPLEMENTED,
|
189
|
+
VM_METHOD_TYPE_OPTIMIZED, /* Kernel#send, Proc#call, etc */
|
190
|
+
VM_METHOD_TYPE_MISSING /* wrapper for method_missing(id) */
|
191
|
+
} rb_method_type_t;
|
192
|
+
|
193
|
+
typedef struct rb_method_cfunc_struct {
|
194
|
+
VALUE (*func)(ANYARGS);
|
195
|
+
int argc;
|
196
|
+
} rb_method_cfunc_t;
|
197
|
+
|
198
|
+
typedef struct rb_method_attr_struct {
|
199
|
+
ID id;
|
200
|
+
VALUE location;
|
201
|
+
} rb_method_attr_t;
|
202
|
+
|
203
|
+
typedef struct rb_iseq_struct rb_iseq_t;
|
204
|
+
|
205
|
+
typedef struct rb_method_definition_struct {
|
206
|
+
rb_method_type_t type; /* method type */
|
207
|
+
ID original_id;
|
208
|
+
union {
|
209
|
+
rb_iseq_t *iseq; /* should be mark */
|
210
|
+
rb_method_cfunc_t cfunc;
|
211
|
+
rb_method_attr_t attr;
|
212
|
+
VALUE proc; /* should be mark */
|
213
|
+
enum method_optimized_type {
|
214
|
+
OPTIMIZED_METHOD_TYPE_SEND,
|
215
|
+
OPTIMIZED_METHOD_TYPE_CALL
|
216
|
+
} optimize_type;
|
217
|
+
} body;
|
218
|
+
int alias_count;
|
219
|
+
} rb_method_definition_t;
|
220
|
+
|
221
|
+
typedef struct rb_method_entry_struct {
|
222
|
+
rb_method_flag_t flag;
|
223
|
+
char mark;
|
224
|
+
rb_method_definition_t *def;
|
225
|
+
ID called_id;
|
226
|
+
VALUE klass; /* should be mark */
|
227
|
+
} rb_method_entry_t;
|
228
|
+
|
229
|
+
struct unlinked_method_entry_list_entry {
|
230
|
+
struct unlinked_method_entry_list_entry *next;
|
231
|
+
rb_method_entry_t *me;
|
232
|
+
};
|
233
|
+
|
234
|
+
#define UNDEFINED_METHOD_ENTRY_P(me) (!(me) || !(me)->def || (me)->def->type == VM_METHOD_TYPE_UNDEF)
|
235
|
+
|
236
|
+
rb_method_entry_t *rb_method_entry(VALUE klass, ID id);
|
237
|
+
|
238
|
+
/* Copy from vm_core.h */
|
239
|
+
|
240
|
+
#define GetCoreDataFromValue(obj, type, ptr) do { \
|
241
|
+
ptr = (type*)DATA_PTR(obj); \
|
242
|
+
} while (0)
|
243
|
+
|
244
|
+
typedef struct rb_block_struct {
|
245
|
+
VALUE self; /* share with method frame if it's only block */
|
246
|
+
VALUE *lfp; /* share with method frame if it's only block */
|
247
|
+
VALUE *dfp; /* share with method frame if it's only block */
|
248
|
+
rb_iseq_t *iseq;
|
249
|
+
VALUE proc;
|
250
|
+
} rb_block_t;
|
251
|
+
|
252
|
+
#define GetProcPtr(obj, ptr) \
|
253
|
+
GetCoreDataFromValue(obj, rb_proc_t, ptr)
|
254
|
+
|
255
|
+
typedef struct {
|
256
|
+
rb_block_t block;
|
257
|
+
|
258
|
+
VALUE envval; /* for GC mark */
|
259
|
+
VALUE blockprocval;
|
260
|
+
int safe_level;
|
261
|
+
int is_from_method;
|
262
|
+
int is_lambda;
|
263
|
+
} rb_proc_t;
|
264
|
+
|
265
|
+
#define GetEnvPtr(obj, ptr) \
|
266
|
+
GetCoreDataFromValue(obj, rb_env_t, ptr)
|
267
|
+
|
268
|
+
typedef struct {
|
269
|
+
VALUE *env;
|
270
|
+
int env_size;
|
271
|
+
int local_size;
|
272
|
+
VALUE prev_envval; /* for GC mark */
|
273
|
+
rb_block_t block;
|
274
|
+
} rb_env_t;
|
275
|
+
|
276
|
+
#define GetBindingPtr(obj, ptr) \
|
277
|
+
GetCoreDataFromValue(obj, rb_binding_t, ptr)
|
278
|
+
|
279
|
+
typedef struct {
|
280
|
+
VALUE env;
|
281
|
+
VALUE filename;
|
282
|
+
unsigned short line_no;
|
283
|
+
} rb_binding_t;
|
284
|
+
|
285
|
+
rb_iseq_t *rb_method_get_iseq(VALUE method);
|
data/lib/ytljit/asm.rb
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
module YTLJit
|
2
|
+
|
3
|
+
class StepHandler
|
4
|
+
REG_NAME = ["EAX", "ECX", "EDX", "EBX", "EBP", "ESP", "EDI"]
|
5
|
+
def step_handler(*regs)
|
6
|
+
STDERR.print "#{regs[0].to_s(16)} "
|
7
|
+
STDERR.print CodeSpace.disasm_cache[regs[0].to_s(16)], "\n"
|
8
|
+
regs.each_with_index do |val, i|
|
9
|
+
STDERR.print REG_NAME[i]
|
10
|
+
STDERR.print ": 0x"
|
11
|
+
STDERR.print val.to_s(16)
|
12
|
+
STDERR.print " "
|
13
|
+
end
|
14
|
+
STDERR.print "\n"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Generator
|
19
|
+
def initialize(asm)
|
20
|
+
@asm = asm
|
21
|
+
end
|
22
|
+
attr :asm
|
23
|
+
end
|
24
|
+
|
25
|
+
class OutputStream
|
26
|
+
def asm=(a)
|
27
|
+
@asm = a
|
28
|
+
end
|
29
|
+
|
30
|
+
def base_address
|
31
|
+
0
|
32
|
+
end
|
33
|
+
|
34
|
+
def var_base_address(offset = 0)
|
35
|
+
OpVarMemAddress.new(lambda {offset})
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class FileOutputStream<OutputStream
|
40
|
+
def initialize(st)
|
41
|
+
@stream = st
|
42
|
+
end
|
43
|
+
|
44
|
+
def emit(code)
|
45
|
+
@stream.write(code)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class DummyOutputStream<OutputStream
|
50
|
+
def initialize(st)
|
51
|
+
end
|
52
|
+
|
53
|
+
def emit(code)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class Assembler
|
58
|
+
@@value_table_cache = {}
|
59
|
+
@@value_table_entity = ValueSpace.new
|
60
|
+
|
61
|
+
def self.set_value_table(out)
|
62
|
+
@@value_table_cache = {}
|
63
|
+
@@value_table_entity = out
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.get_value_table(out)
|
67
|
+
[@@value_table_entity, @@value_table_cache]
|
68
|
+
end
|
69
|
+
|
70
|
+
def initialize(out, gen = GeneratorExtend)
|
71
|
+
@generator = gen.new(self)
|
72
|
+
@output_stream = out
|
73
|
+
@retry_mode = false
|
74
|
+
@step_mode = false
|
75
|
+
@asmsend_history = []
|
76
|
+
|
77
|
+
# Instruction pach table for forwarding reference
|
78
|
+
# This is array of proc object.
|
79
|
+
@after_patch_tab = []
|
80
|
+
reset
|
81
|
+
end
|
82
|
+
|
83
|
+
def reset
|
84
|
+
@current_address = @output_stream.base_address
|
85
|
+
@offset = 0
|
86
|
+
end
|
87
|
+
|
88
|
+
attr_accessor :current_address
|
89
|
+
attr_accessor :step_mode
|
90
|
+
attr :offset
|
91
|
+
attr :output_stream
|
92
|
+
attr :after_patch_tab
|
93
|
+
attr :retry_mode
|
94
|
+
|
95
|
+
def var_current_address
|
96
|
+
current_address = @current_address
|
97
|
+
|
98
|
+
func = lambda {
|
99
|
+
current_address
|
100
|
+
}
|
101
|
+
OpVarMemAddress.new(func)
|
102
|
+
end
|
103
|
+
|
104
|
+
attr_accessor :generated_code
|
105
|
+
|
106
|
+
def store_outcode(out)
|
107
|
+
update_state(out)
|
108
|
+
@offset += out.bytesize
|
109
|
+
@output_stream.emit(out)
|
110
|
+
out
|
111
|
+
end
|
112
|
+
|
113
|
+
def update_state(out)
|
114
|
+
@current_address += out.bytesize
|
115
|
+
out
|
116
|
+
end
|
117
|
+
|
118
|
+
def with_retry(&body)
|
119
|
+
org_base_address = @output_stream.base_address
|
120
|
+
yield
|
121
|
+
|
122
|
+
org_retry_mode = @retry_mode
|
123
|
+
@retry_mode = :change_org
|
124
|
+
while org_base_address != @output_stream.base_address do
|
125
|
+
org_base_address = @output_stream.base_address
|
126
|
+
reset
|
127
|
+
@output_stream.reset
|
128
|
+
@asmsend_history.each do |arg|
|
129
|
+
send(arg[0], *arg[1])
|
130
|
+
end
|
131
|
+
@output_stream.update_refer
|
132
|
+
end
|
133
|
+
|
134
|
+
@after_patch_tab.each do |patproc|
|
135
|
+
patproc.call
|
136
|
+
end
|
137
|
+
@retry_mode = org_retry_mode
|
138
|
+
end
|
139
|
+
|
140
|
+
def add_value_entry(val)
|
141
|
+
off= nil
|
142
|
+
unless off = @@value_table_cache[val] then
|
143
|
+
off = @@value_table_entity.current_pos
|
144
|
+
@@value_table_entity.emit([val.value].pack("Q"))
|
145
|
+
@@value_table_cache[val] = off
|
146
|
+
end
|
147
|
+
|
148
|
+
@@value_table_entity.var_base_address(off)
|
149
|
+
end
|
150
|
+
|
151
|
+
def add_var_value_retry_func(mn, args)
|
152
|
+
if args.any? {|e| e.is_a?(OpVarValueMixin) } and
|
153
|
+
@retry_mode == false then
|
154
|
+
offset = @offset
|
155
|
+
stfunc = lambda {
|
156
|
+
with_current_address(@output_stream.base_address + offset) {
|
157
|
+
orgretry_mode = @retry_mode
|
158
|
+
@retry_mode = :change_op
|
159
|
+
out = @generator.send(mn, *args)
|
160
|
+
if out.is_a?(Array)
|
161
|
+
@output_stream[offset] = out[0]
|
162
|
+
else
|
163
|
+
@output_stream[offset] = out
|
164
|
+
end
|
165
|
+
@retry_mode = orgretry_mode
|
166
|
+
}
|
167
|
+
}
|
168
|
+
args.each do |e|
|
169
|
+
if e.is_a?(OpVarValueMixin) then
|
170
|
+
e.add_refer(stfunc)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def method_missing(mn, *args)
|
177
|
+
out = @generator.call_stephandler
|
178
|
+
store_outcode(out)
|
179
|
+
|
180
|
+
if @retry_mode == false then
|
181
|
+
case mn
|
182
|
+
when :call_with_arg
|
183
|
+
args.push(@generator.call_with_arg_get_argsize(*args))
|
184
|
+
end
|
185
|
+
@asmsend_history.push [mn, args]
|
186
|
+
end
|
187
|
+
|
188
|
+
add_var_value_retry_func(mn, args)
|
189
|
+
out = @generator.send(mn, *args)
|
190
|
+
if out.is_a?(Array) then
|
191
|
+
store_outcode(out[0])
|
192
|
+
else
|
193
|
+
store_outcode(out)
|
194
|
+
end
|
195
|
+
out
|
196
|
+
end
|
197
|
+
|
198
|
+
def with_current_address(address)
|
199
|
+
org_curret_address = self.current_address
|
200
|
+
self.current_address = address
|
201
|
+
yield
|
202
|
+
self.current_address = org_curret_address
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
#---------
|
2
|
+
# Extended Specication of Assembler Level Layer
|
3
|
+
#
|
4
|
+
module YTLJit
|
5
|
+
class TypedData
|
6
|
+
include AbsArch
|
7
|
+
|
8
|
+
def initialize(type, ent)
|
9
|
+
@type = type
|
10
|
+
@entity = ent
|
11
|
+
end
|
12
|
+
|
13
|
+
attr :type
|
14
|
+
attr :entity
|
15
|
+
|
16
|
+
def [](arg)
|
17
|
+
TypedData.new(@type[arg], @entity)
|
18
|
+
end
|
19
|
+
|
20
|
+
def gen_access(gen)
|
21
|
+
asm = gen.asm
|
22
|
+
base = @entity
|
23
|
+
case @type
|
24
|
+
when AsmType::Scalar, AsmType::Pointer, AsmType::Array
|
25
|
+
if base != TMPR then
|
26
|
+
code = ""
|
27
|
+
code += asm.update_state(gen.mov(TMPR, base))
|
28
|
+
[code, @type]
|
29
|
+
else
|
30
|
+
["", @type]
|
31
|
+
end
|
32
|
+
|
33
|
+
when AsmType::StructMember
|
34
|
+
code = ""
|
35
|
+
if base != TMPR then
|
36
|
+
code += asm.update_state(gen.mov(TMPR, base))
|
37
|
+
end
|
38
|
+
oi = OpIndirect.new(TMPR, @type.offset)
|
39
|
+
if @type.type.is_a?(AsmType::Array) then
|
40
|
+
code += asm.update_state(gen.call_stephandler) if code != ""
|
41
|
+
code += asm.update_state(gen.lea(TMPR, oi))
|
42
|
+
else
|
43
|
+
code += asm.update_state(gen.call_stephandler) if code != ""
|
44
|
+
code += asm.update_state(gen.mov(TMPR, oi))
|
45
|
+
end
|
46
|
+
[code, @type.type]
|
47
|
+
|
48
|
+
when AsmType::PointedData
|
49
|
+
# Now support only index == 0
|
50
|
+
code = ""
|
51
|
+
if base != TMPR then
|
52
|
+
code += asm.update_state(gen.mov(TMPR, base))
|
53
|
+
end
|
54
|
+
if @type.offset != 0 then
|
55
|
+
oi = OpIndirect.new(TMPR, @type.offset)
|
56
|
+
code += asm.update_state(gen.call_stephandler) if code != ""
|
57
|
+
code += asm.update_state(gen.lea(TMPR, oi))
|
58
|
+
end
|
59
|
+
ineax = OpIndirect.new(TMPR)
|
60
|
+
code += asm.update_state(gen.call_stephandler) if code != ""
|
61
|
+
code += asm.update_state(gen.mov(TMPR, ineax))
|
62
|
+
[code, @type.type]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class FunctionArgument
|
68
|
+
def initialize(no, kind)
|
69
|
+
@no = no
|
70
|
+
@abi_kind = kind
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class FunctionArgumentInt<FunctionArgument
|
75
|
+
case $ruby_platform
|
76
|
+
when /x86_64/
|
77
|
+
include FunctionArgumentX64MixinCommon
|
78
|
+
include FunctionArgumentX64MixinInt
|
79
|
+
|
80
|
+
when /i.86/
|
81
|
+
include FunctionArgumentX86Mixin
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class FunctionArgumentFloat<FunctionArgument
|
86
|
+
case $ruby_platform
|
87
|
+
when /x86_64/
|
88
|
+
include FunctionArgumentX64MixinCommon
|
89
|
+
include FunctionArgumentX64MixinFloat
|
90
|
+
|
91
|
+
when /i.86/
|
92
|
+
include FunctionArgumentX86Mixin
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class FuncArgInfo
|
97
|
+
def initialize
|
98
|
+
@maxargs = 0
|
99
|
+
@used_arg_tab = []
|
100
|
+
@area_allocate_pos = []
|
101
|
+
end
|
102
|
+
|
103
|
+
attr_accessor :used_arg_tab
|
104
|
+
attr :maxargs
|
105
|
+
attr :area_allocate_pos
|
106
|
+
|
107
|
+
def update_maxargs(args)
|
108
|
+
if @maxargs < args then
|
109
|
+
@maxargs = args
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
module GeneratorExtendMixin
|
115
|
+
include AbsArch
|
116
|
+
|
117
|
+
def initialize(asm, handler = "ytl_step_handler")
|
118
|
+
super
|
119
|
+
@funcarg_info = FuncArgInfo.new
|
120
|
+
end
|
121
|
+
attr :funcarg_info
|
122
|
+
|
123
|
+
def nosupported_addressing_mode(inst, dst, src, src2 = nil)
|
124
|
+
case inst
|
125
|
+
when :mov
|
126
|
+
case src
|
127
|
+
when TypedData
|
128
|
+
orgaddress = @asm.current_address
|
129
|
+
rcode = ""
|
130
|
+
rcode, rtype = src.gen_access(self)
|
131
|
+
if dst != TMPR then
|
132
|
+
rcode += @asm.update_state(call_stephandler) if rcode != ""
|
133
|
+
rcode += @asm.update_state(mov(dst, TMPR))
|
134
|
+
end
|
135
|
+
@asm.current_address = orgaddress
|
136
|
+
return [rcode, TypedData.new(rtype, dst)]
|
137
|
+
end
|
138
|
+
|
139
|
+
when :seta, :setae, :setb, :setbe, :setl, :setle, :setg, :setge,
|
140
|
+
:setna, :setnae, :setnb, :setnbe, :setnc, :setnle,
|
141
|
+
:setno, :seto, :setz, :setnz
|
142
|
+
case dst
|
143
|
+
when OpReg32, OpReg64
|
144
|
+
rcode = ""
|
145
|
+
reg8 = [AL, CL, DL, BL][dst.reg_no]
|
146
|
+
rcode += send(inst, reg8)
|
147
|
+
rcode += self.and(dst, 1)
|
148
|
+
return rcode
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
case src
|
153
|
+
when FunctionArgument
|
154
|
+
orgaddress = @asm.current_address
|
155
|
+
rcode = ""
|
156
|
+
rcode = src.gen_access_src(self, inst, dst, src, src2)
|
157
|
+
rcode += @asm.update_state(call_stephandler)
|
158
|
+
@asm.current_address = orgaddress
|
159
|
+
return rcode
|
160
|
+
|
161
|
+
when OpRegXMM
|
162
|
+
case inst
|
163
|
+
when :mov
|
164
|
+
return movsd(dst, src)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
case dst
|
169
|
+
when FunctionArgument
|
170
|
+
orgaddress = @asm.current_address
|
171
|
+
rcode = ""
|
172
|
+
rcode = dst.gen_access_dst(self, inst, dst, src, src2)
|
173
|
+
rcode += @asm.update_state(call_stephandler)
|
174
|
+
@asm.current_address = orgaddress
|
175
|
+
return rcode
|
176
|
+
|
177
|
+
when OpRegXMM
|
178
|
+
case inst
|
179
|
+
when :mov
|
180
|
+
return movsd(dst, src)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
super
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
class GeneratorExtend<GeneratorIABinary
|
189
|
+
include GeneratorExtendMixin
|
190
|
+
|
191
|
+
case $ruby_platform
|
192
|
+
when /x86_64/
|
193
|
+
include GeneratorExtendX64Mixin
|
194
|
+
|
195
|
+
when /i.86/
|
196
|
+
include GeneratorExtendX86Mixin
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|