node-marshal 0.1.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.
- checksums.yaml +7 -0
- data/README.rdoc +18 -0
- data/bin/noderbc +27 -0
- data/bin/noderbc.bat +1 -0
- data/ext/node-marshal/COPYING +23 -0
- data/ext/node-marshal/base85r.c +190 -0
- data/ext/node-marshal/extconf.rb +3 -0
- data/ext/node-marshal/libobj/readme.txt +1 -0
- data/ext/node-marshal/node193.h +312 -0
- data/ext/node-marshal/node220.h +338 -0
- data/ext/node-marshal/nodedump.c +1804 -0
- data/ext/node-marshal/nodedump.h +67 -0
- data/ext/node-marshal/nodeinfo.c +466 -0
- data/lib/node-marshal.rb +64 -0
- data/test/lifegame.rb +145 -0
- data/test/test_base.rb +161 -0
- data/test/test_complex.rb +133 -0
- data/test/test_lifegame.rb +68 -0
- data/test/tinytet.rb +79 -0
- metadata +72 -0
@@ -0,0 +1,338 @@
|
|
1
|
+
/*
|
2
|
+
* Simpilfied node.h file from Ruby 2.2.1 source code
|
3
|
+
* Copyright (C) 1993-2007 Yukihiro Matsumoto
|
4
|
+
*/
|
5
|
+
#ifndef RUBY_NODE_H
|
6
|
+
#define RUBY_NODE_H 1
|
7
|
+
|
8
|
+
#if defined(__cplusplus)
|
9
|
+
extern "C" {
|
10
|
+
#if 0
|
11
|
+
} /* satisfy cc-mode */
|
12
|
+
#endif
|
13
|
+
#endif
|
14
|
+
|
15
|
+
enum node_type {
|
16
|
+
NODE_SCOPE,
|
17
|
+
#define NODE_SCOPE NODE_SCOPE
|
18
|
+
NODE_BLOCK,
|
19
|
+
#define NODE_BLOCK NODE_BLOCK
|
20
|
+
NODE_IF,
|
21
|
+
#define NODE_IF NODE_IF
|
22
|
+
NODE_CASE,
|
23
|
+
#define NODE_CASE NODE_CASE
|
24
|
+
NODE_WHEN,
|
25
|
+
#define NODE_WHEN NODE_WHEN
|
26
|
+
NODE_OPT_N,
|
27
|
+
#define NODE_OPT_N NODE_OPT_N
|
28
|
+
NODE_WHILE,
|
29
|
+
#define NODE_WHILE NODE_WHILE
|
30
|
+
NODE_UNTIL,
|
31
|
+
#define NODE_UNTIL NODE_UNTIL
|
32
|
+
NODE_ITER,
|
33
|
+
#define NODE_ITER NODE_ITER
|
34
|
+
NODE_FOR,
|
35
|
+
#define NODE_FOR NODE_FOR
|
36
|
+
NODE_BREAK,
|
37
|
+
#define NODE_BREAK NODE_BREAK
|
38
|
+
NODE_NEXT,
|
39
|
+
#define NODE_NEXT NODE_NEXT
|
40
|
+
NODE_REDO,
|
41
|
+
#define NODE_REDO NODE_REDO
|
42
|
+
NODE_RETRY,
|
43
|
+
#define NODE_RETRY NODE_RETRY
|
44
|
+
NODE_BEGIN,
|
45
|
+
#define NODE_BEGIN NODE_BEGIN
|
46
|
+
NODE_RESCUE,
|
47
|
+
#define NODE_RESCUE NODE_RESCUE
|
48
|
+
NODE_RESBODY,
|
49
|
+
#define NODE_RESBODY NODE_RESBODY
|
50
|
+
NODE_ENSURE,
|
51
|
+
#define NODE_ENSURE NODE_ENSURE
|
52
|
+
NODE_AND,
|
53
|
+
#define NODE_AND NODE_AND
|
54
|
+
NODE_OR,
|
55
|
+
#define NODE_OR NODE_OR
|
56
|
+
NODE_MASGN,
|
57
|
+
#define NODE_MASGN NODE_MASGN
|
58
|
+
NODE_LASGN,
|
59
|
+
#define NODE_LASGN NODE_LASGN
|
60
|
+
NODE_DASGN,
|
61
|
+
#define NODE_DASGN NODE_DASGN
|
62
|
+
NODE_DASGN_CURR,
|
63
|
+
#define NODE_DASGN_CURR NODE_DASGN_CURR
|
64
|
+
NODE_GASGN,
|
65
|
+
#define NODE_GASGN NODE_GASGN
|
66
|
+
NODE_IASGN,
|
67
|
+
#define NODE_IASGN NODE_IASGN
|
68
|
+
NODE_IASGN2,
|
69
|
+
#define NODE_IASGN2 NODE_IASGN2
|
70
|
+
NODE_CDECL,
|
71
|
+
#define NODE_CDECL NODE_CDECL
|
72
|
+
NODE_CVASGN,
|
73
|
+
#define NODE_CVASGN NODE_CVASGN
|
74
|
+
NODE_CVDECL,
|
75
|
+
#define NODE_CVDECL NODE_CVDECL
|
76
|
+
NODE_OP_ASGN1,
|
77
|
+
#define NODE_OP_ASGN1 NODE_OP_ASGN1
|
78
|
+
NODE_OP_ASGN2,
|
79
|
+
#define NODE_OP_ASGN2 NODE_OP_ASGN2
|
80
|
+
NODE_OP_ASGN_AND,
|
81
|
+
#define NODE_OP_ASGN_AND NODE_OP_ASGN_AND
|
82
|
+
NODE_OP_ASGN_OR,
|
83
|
+
#define NODE_OP_ASGN_OR NODE_OP_ASGN_OR
|
84
|
+
NODE_OP_CDECL,
|
85
|
+
#define NODE_OP_CDECL NODE_OP_CDECL
|
86
|
+
NODE_CALL,
|
87
|
+
#define NODE_CALL NODE_CALL
|
88
|
+
NODE_FCALL,
|
89
|
+
#define NODE_FCALL NODE_FCALL
|
90
|
+
NODE_VCALL,
|
91
|
+
#define NODE_VCALL NODE_VCALL
|
92
|
+
NODE_SUPER,
|
93
|
+
#define NODE_SUPER NODE_SUPER
|
94
|
+
NODE_ZSUPER,
|
95
|
+
#define NODE_ZSUPER NODE_ZSUPER
|
96
|
+
NODE_ARRAY,
|
97
|
+
#define NODE_ARRAY NODE_ARRAY
|
98
|
+
NODE_ZARRAY,
|
99
|
+
#define NODE_ZARRAY NODE_ZARRAY
|
100
|
+
NODE_VALUES,
|
101
|
+
#define NODE_VALUES NODE_VALUES
|
102
|
+
NODE_HASH,
|
103
|
+
#define NODE_HASH NODE_HASH
|
104
|
+
NODE_RETURN,
|
105
|
+
#define NODE_RETURN NODE_RETURN
|
106
|
+
NODE_YIELD,
|
107
|
+
#define NODE_YIELD NODE_YIELD
|
108
|
+
NODE_LVAR,
|
109
|
+
#define NODE_LVAR NODE_LVAR
|
110
|
+
NODE_DVAR,
|
111
|
+
#define NODE_DVAR NODE_DVAR
|
112
|
+
NODE_GVAR,
|
113
|
+
#define NODE_GVAR NODE_GVAR
|
114
|
+
NODE_IVAR,
|
115
|
+
#define NODE_IVAR NODE_IVAR
|
116
|
+
NODE_CONST,
|
117
|
+
#define NODE_CONST NODE_CONST
|
118
|
+
NODE_CVAR,
|
119
|
+
#define NODE_CVAR NODE_CVAR
|
120
|
+
NODE_NTH_REF,
|
121
|
+
#define NODE_NTH_REF NODE_NTH_REF
|
122
|
+
NODE_BACK_REF,
|
123
|
+
#define NODE_BACK_REF NODE_BACK_REF
|
124
|
+
NODE_MATCH,
|
125
|
+
#define NODE_MATCH NODE_MATCH
|
126
|
+
NODE_MATCH2,
|
127
|
+
#define NODE_MATCH2 NODE_MATCH2
|
128
|
+
NODE_MATCH3,
|
129
|
+
#define NODE_MATCH3 NODE_MATCH3
|
130
|
+
NODE_LIT,
|
131
|
+
#define NODE_LIT NODE_LIT
|
132
|
+
NODE_STR,
|
133
|
+
#define NODE_STR NODE_STR
|
134
|
+
NODE_DSTR,
|
135
|
+
#define NODE_DSTR NODE_DSTR
|
136
|
+
NODE_XSTR,
|
137
|
+
#define NODE_XSTR NODE_XSTR
|
138
|
+
NODE_DXSTR,
|
139
|
+
#define NODE_DXSTR NODE_DXSTR
|
140
|
+
NODE_EVSTR,
|
141
|
+
#define NODE_EVSTR NODE_EVSTR
|
142
|
+
NODE_DREGX,
|
143
|
+
#define NODE_DREGX NODE_DREGX
|
144
|
+
NODE_DREGX_ONCE,
|
145
|
+
#define NODE_DREGX_ONCE NODE_DREGX_ONCE
|
146
|
+
NODE_ARGS,
|
147
|
+
#define NODE_ARGS NODE_ARGS
|
148
|
+
NODE_ARGS_AUX,
|
149
|
+
#define NODE_ARGS_AUX NODE_ARGS_AUX
|
150
|
+
NODE_OPT_ARG,
|
151
|
+
#define NODE_OPT_ARG NODE_OPT_ARG
|
152
|
+
NODE_KW_ARG,
|
153
|
+
#define NODE_KW_ARG NODE_KW_ARG
|
154
|
+
NODE_POSTARG,
|
155
|
+
#define NODE_POSTARG NODE_POSTARG
|
156
|
+
NODE_ARGSCAT,
|
157
|
+
#define NODE_ARGSCAT NODE_ARGSCAT
|
158
|
+
NODE_ARGSPUSH,
|
159
|
+
#define NODE_ARGSPUSH NODE_ARGSPUSH
|
160
|
+
NODE_SPLAT,
|
161
|
+
#define NODE_SPLAT NODE_SPLAT
|
162
|
+
NODE_TO_ARY,
|
163
|
+
#define NODE_TO_ARY NODE_TO_ARY
|
164
|
+
NODE_BLOCK_ARG,
|
165
|
+
#define NODE_BLOCK_ARG NODE_BLOCK_ARG
|
166
|
+
NODE_BLOCK_PASS,
|
167
|
+
#define NODE_BLOCK_PASS NODE_BLOCK_PASS
|
168
|
+
NODE_DEFN,
|
169
|
+
#define NODE_DEFN NODE_DEFN
|
170
|
+
NODE_DEFS,
|
171
|
+
#define NODE_DEFS NODE_DEFS
|
172
|
+
NODE_ALIAS,
|
173
|
+
#define NODE_ALIAS NODE_ALIAS
|
174
|
+
NODE_VALIAS,
|
175
|
+
#define NODE_VALIAS NODE_VALIAS
|
176
|
+
NODE_UNDEF,
|
177
|
+
#define NODE_UNDEF NODE_UNDEF
|
178
|
+
NODE_CLASS,
|
179
|
+
#define NODE_CLASS NODE_CLASS
|
180
|
+
NODE_MODULE,
|
181
|
+
#define NODE_MODULE NODE_MODULE
|
182
|
+
NODE_SCLASS,
|
183
|
+
#define NODE_SCLASS NODE_SCLASS
|
184
|
+
NODE_COLON2,
|
185
|
+
#define NODE_COLON2 NODE_COLON2
|
186
|
+
NODE_COLON3,
|
187
|
+
#define NODE_COLON3 NODE_COLON3
|
188
|
+
NODE_CREF,
|
189
|
+
#define NODE_CREF NODE_CREF
|
190
|
+
NODE_DOT2,
|
191
|
+
#define NODE_DOT2 NODE_DOT2
|
192
|
+
NODE_DOT3,
|
193
|
+
#define NODE_DOT3 NODE_DOT3
|
194
|
+
NODE_FLIP2,
|
195
|
+
#define NODE_FLIP2 NODE_FLIP2
|
196
|
+
NODE_FLIP3,
|
197
|
+
#define NODE_FLIP3 NODE_FLIP3
|
198
|
+
NODE_SELF,
|
199
|
+
#define NODE_SELF NODE_SELF
|
200
|
+
NODE_NIL,
|
201
|
+
#define NODE_NIL NODE_NIL
|
202
|
+
NODE_TRUE,
|
203
|
+
#define NODE_TRUE NODE_TRUE
|
204
|
+
NODE_FALSE,
|
205
|
+
#define NODE_FALSE NODE_FALSE
|
206
|
+
NODE_ERRINFO,
|
207
|
+
#define NODE_ERRINFO NODE_ERRINFO
|
208
|
+
NODE_DEFINED,
|
209
|
+
#define NODE_DEFINED NODE_DEFINED
|
210
|
+
NODE_POSTEXE,
|
211
|
+
#define NODE_POSTEXE NODE_POSTEXE
|
212
|
+
NODE_ALLOCA,
|
213
|
+
#define NODE_ALLOCA NODE_ALLOCA
|
214
|
+
NODE_BMETHOD,
|
215
|
+
#define NODE_BMETHOD NODE_BMETHOD
|
216
|
+
NODE_MEMO,
|
217
|
+
#define NODE_MEMO NODE_MEMO
|
218
|
+
NODE_IFUNC,
|
219
|
+
#define NODE_IFUNC NODE_IFUNC
|
220
|
+
NODE_DSYM,
|
221
|
+
#define NODE_DSYM NODE_DSYM
|
222
|
+
NODE_ATTRASGN,
|
223
|
+
#define NODE_ATTRASGN NODE_ATTRASGN
|
224
|
+
NODE_PRELUDE,
|
225
|
+
#define NODE_PRELUDE NODE_PRELUDE
|
226
|
+
NODE_LAMBDA,
|
227
|
+
#define NODE_LAMBDA NODE_LAMBDA
|
228
|
+
NODE_LAST
|
229
|
+
#define NODE_LAST NODE_LAST
|
230
|
+
};
|
231
|
+
|
232
|
+
typedef struct RNode {
|
233
|
+
VALUE flags;
|
234
|
+
VALUE nd_reserved; /* ex nd_file */
|
235
|
+
union {
|
236
|
+
struct RNode *node;
|
237
|
+
ID id;
|
238
|
+
VALUE value;
|
239
|
+
VALUE (*cfunc)(ANYARGS);
|
240
|
+
ID *tbl;
|
241
|
+
} u1;
|
242
|
+
union {
|
243
|
+
struct RNode *node;
|
244
|
+
ID id;
|
245
|
+
long argc;
|
246
|
+
VALUE value;
|
247
|
+
} u2;
|
248
|
+
union {
|
249
|
+
struct RNode *node;
|
250
|
+
ID id;
|
251
|
+
long state;
|
252
|
+
struct rb_global_entry *entry;
|
253
|
+
struct rb_args_info *args;
|
254
|
+
long cnt;
|
255
|
+
VALUE value;
|
256
|
+
} u3;
|
257
|
+
} NODE;
|
258
|
+
|
259
|
+
#define RNODE(obj) (R_CAST(RNode)(obj))
|
260
|
+
|
261
|
+
/* FL : 0..4: T_TYPES, 5: KEEP_WB, 6: PROMOTED, 7: FINALIZE, 8: TAINT, 9: UNTRUSTERD, 10: EXIVAR, 11: FREEZE */
|
262
|
+
/* NODE_FL: 0..4: T_TYPES, 5: KEEP_WB, 6: PROMOTED, 7: NODE_FL_NEWLINE|NODE_FL_CREF_PUSHED_BY_EVAL,
|
263
|
+
* 8..14: nd_type,
|
264
|
+
* 15..: nd_line or
|
265
|
+
* 15: NODE_FL_CREF_PUSHED_BY_EVAL
|
266
|
+
* 16: NODE_FL_CREF_OMOD_SHARED
|
267
|
+
*/
|
268
|
+
#define NODE_FL_NEWLINE (((VALUE)1)<<7)
|
269
|
+
#define NODE_FL_CREF_PUSHED_BY_EVAL (((VALUE)1)<<15)
|
270
|
+
#define NODE_FL_CREF_OMOD_SHARED (((VALUE)1)<<16)
|
271
|
+
|
272
|
+
#define NODE_TYPESHIFT 8
|
273
|
+
#define NODE_TYPEMASK (((VALUE)0x7f)<<NODE_TYPESHIFT)
|
274
|
+
|
275
|
+
#define nd_type(n) ((int) (((RNODE(n))->flags & NODE_TYPEMASK)>>NODE_TYPESHIFT))
|
276
|
+
#define nd_set_type(n,t) \
|
277
|
+
RNODE(n)->flags=((RNODE(n)->flags&~NODE_TYPEMASK)|((((unsigned long)(t))<<NODE_TYPESHIFT)&NODE_TYPEMASK))
|
278
|
+
|
279
|
+
#define NODE_LSHIFT (NODE_TYPESHIFT+7)
|
280
|
+
#define NODE_LMASK (((SIGNED_VALUE)1<<(sizeof(VALUE)*CHAR_BIT-NODE_LSHIFT))-1)
|
281
|
+
#define nd_line(n) (int)(RNODE(n)->flags>>NODE_LSHIFT)
|
282
|
+
#define nd_set_line(n,l) \
|
283
|
+
RNODE(n)->flags=((RNODE(n)->flags&~((VALUE)(-1)<<NODE_LSHIFT))|((VALUE)((l)&NODE_LMASK)<<NODE_LSHIFT))
|
284
|
+
|
285
|
+
#define NEW_NODE(t,a0,a1,a2) rb_node_newnode((t),(VALUE)(a0),(VALUE)(a1),(VALUE)(a2))
|
286
|
+
RUBY_SYMBOL_EXPORT_BEGIN
|
287
|
+
|
288
|
+
VALUE rb_parser_dump_tree(NODE *node, int comment);
|
289
|
+
|
290
|
+
NODE *rb_compile_cstr(const char*, const char*, int, int);
|
291
|
+
NODE *rb_compile_string(const char*, VALUE, int);
|
292
|
+
NODE *rb_compile_file(const char*, VALUE, int);
|
293
|
+
|
294
|
+
NODE *rb_node_newnode(enum node_type,VALUE,VALUE,VALUE);
|
295
|
+
NODE *rb_node_newnode_longlife(enum node_type,VALUE,VALUE,VALUE);
|
296
|
+
void rb_gc_free_node(VALUE obj);
|
297
|
+
size_t rb_node_memsize(VALUE obj);
|
298
|
+
VALUE rb_gc_mark_node(NODE *obj);
|
299
|
+
|
300
|
+
struct rb_global_entry {
|
301
|
+
struct rb_global_variable *var;
|
302
|
+
ID id;
|
303
|
+
};
|
304
|
+
|
305
|
+
struct rb_global_entry *rb_global_entry(ID);
|
306
|
+
VALUE rb_gvar_get(struct rb_global_entry *);
|
307
|
+
VALUE rb_gvar_set(struct rb_global_entry *, VALUE);
|
308
|
+
VALUE rb_gvar_defined(struct rb_global_entry *);
|
309
|
+
const struct kwtable *rb_reserved_word(const char *, unsigned int);
|
310
|
+
|
311
|
+
struct rb_args_info {
|
312
|
+
NODE *pre_init;
|
313
|
+
NODE *post_init;
|
314
|
+
|
315
|
+
int pre_args_num; /* count of mandatory pre-arguments */
|
316
|
+
int post_args_num; /* count of mandatory post-arguments */
|
317
|
+
|
318
|
+
ID first_post_arg;
|
319
|
+
|
320
|
+
ID rest_arg;
|
321
|
+
ID block_arg;
|
322
|
+
|
323
|
+
NODE *kw_args;
|
324
|
+
NODE *kw_rest_arg;
|
325
|
+
|
326
|
+
NODE *opt_args;
|
327
|
+
};
|
328
|
+
|
329
|
+
RUBY_SYMBOL_EXPORT_END
|
330
|
+
|
331
|
+
#if defined(__cplusplus)
|
332
|
+
#if 0
|
333
|
+
{ /* satisfy cc-mode */
|
334
|
+
#endif
|
335
|
+
} /* extern "C" { */
|
336
|
+
#endif
|
337
|
+
|
338
|
+
#endif /* RUBY_NODE_H */
|
@@ -0,0 +1,1804 @@
|
|
1
|
+
/*
|
2
|
+
* This file contains implementation of classes for Ruby nodes
|
3
|
+
* marshalization (i.e. loading and saving them from disk)
|
4
|
+
*
|
5
|
+
* (C) 2015 Alexey Voskov
|
6
|
+
* License: 2-clause BSD
|
7
|
+
*/
|
8
|
+
#define __STDC_FORMAT_MACROS
|
9
|
+
#include <stdio.h>
|
10
|
+
#include <stdlib.h>
|
11
|
+
#include <inttypes.h>
|
12
|
+
#include <ruby.h>
|
13
|
+
#include <ruby/version.h>
|
14
|
+
|
15
|
+
/*
|
16
|
+
* Some global variables
|
17
|
+
*/
|
18
|
+
static VALUE cNodeObjAddresses, cNodeInfo;
|
19
|
+
|
20
|
+
/*
|
21
|
+
* Part 1. "Citations" from Ruby 2.2.1 internal include files
|
22
|
+
*/
|
23
|
+
#include "nodedump.h"
|
24
|
+
|
25
|
+
|
26
|
+
/*
|
27
|
+
* Part 2. Information about the nodes
|
28
|
+
*
|
29
|
+
*/
|
30
|
+
|
31
|
+
// Pre-2.0 Ruby versions don't use this version
|
32
|
+
#if RUBY_API_VERSION_MAJOR == 2
|
33
|
+
#define USE_RB_ARGS_INFO 1
|
34
|
+
#endif
|
35
|
+
|
36
|
+
#if RUBY_API_VERSION_MAJOR == 1
|
37
|
+
#define RESET_GC_FLAGS 1
|
38
|
+
#endif
|
39
|
+
|
40
|
+
|
41
|
+
// Some generic utilities
|
42
|
+
int is_value_in_heap(VALUE val)
|
43
|
+
{
|
44
|
+
if (val == Qfalse || val == Qtrue ||
|
45
|
+
val == Qnil || val == Qundef ||
|
46
|
+
(val & FIXNUM_FLAG)
|
47
|
+
#ifdef FLONUM_MASK
|
48
|
+
|| ((val & FLONUM_MASK) == FLONUM_FLAG) // This memory trick with floats is present only in 2.x
|
49
|
+
#endif
|
50
|
+
)
|
51
|
+
{
|
52
|
+
return 0;
|
53
|
+
}
|
54
|
+
else
|
55
|
+
return 1;
|
56
|
+
}
|
57
|
+
|
58
|
+
|
59
|
+
/*
|
60
|
+
* Converts Ruby string with hexadecimal number
|
61
|
+
* to the Ruby VALUE
|
62
|
+
*/
|
63
|
+
VALUE str_to_value(VALUE str)
|
64
|
+
{
|
65
|
+
intptr_t ans = (intptr_t) Qnil;
|
66
|
+
sscanf(RSTRING_PTR(str), "%"PRIxPTR, &ans);
|
67
|
+
return (VALUE) ans;
|
68
|
+
}
|
69
|
+
|
70
|
+
|
71
|
+
/*
|
72
|
+
* Converts Ruby VALUE (i.e. machine address) to the
|
73
|
+
* hexadecimal Ruby string
|
74
|
+
*/
|
75
|
+
VALUE value_to_str(VALUE val)
|
76
|
+
{
|
77
|
+
char str[16];
|
78
|
+
sprintf(str, "%" PRIxPTR, (intptr_t) val);
|
79
|
+
return rb_str_new2(str);
|
80
|
+
}
|
81
|
+
|
82
|
+
/*
|
83
|
+
* Converts VALUE to the sequence of bytes using big-endian
|
84
|
+
* standard. Returns number of non-zero bytes
|
85
|
+
*
|
86
|
+
* Inputs
|
87
|
+
* val -- input value
|
88
|
+
* buf -- pointer to the output buffer
|
89
|
+
* Returns
|
90
|
+
* number of written bytes
|
91
|
+
*/
|
92
|
+
int value_to_bin(VALUE val, unsigned char *buf)
|
93
|
+
{
|
94
|
+
int i, len = 0;
|
95
|
+
unsigned char byte;
|
96
|
+
for (i = sizeof(VALUE) - 1; i >= 0; i--)
|
97
|
+
{
|
98
|
+
byte = (unsigned char) ((val >> (i * 8)) & 0xFF);
|
99
|
+
if (len > 0 || byte != 0)
|
100
|
+
{
|
101
|
+
*buf++ = byte;
|
102
|
+
len++;
|
103
|
+
}
|
104
|
+
}
|
105
|
+
return len;
|
106
|
+
}
|
107
|
+
|
108
|
+
/*
|
109
|
+
* Converts sequence of bytes (big-endian standard) to the VALUE.
|
110
|
+
*
|
111
|
+
* Inputs
|
112
|
+
* buf -- poiner to the input buffer
|
113
|
+
* len -- number of bytes
|
114
|
+
* Returns
|
115
|
+
* VALUE
|
116
|
+
*/
|
117
|
+
VALUE bin_to_value(unsigned char *buf, int len)
|
118
|
+
{
|
119
|
+
VALUE val = (VALUE) 0;
|
120
|
+
int i;
|
121
|
+
for (i = len - 1; i >= 0; i--)
|
122
|
+
val |= ((VALUE) *buf++) << (i * 8);
|
123
|
+
return val;
|
124
|
+
}
|
125
|
+
|
126
|
+
#define NODES_CTBL_SIZE 256
|
127
|
+
static int nodes_ctbl[NODES_CTBL_SIZE * 3];
|
128
|
+
|
129
|
+
|
130
|
+
/*
|
131
|
+
* Part 3. Functions for node marshalization
|
132
|
+
*/
|
133
|
+
|
134
|
+
/*
|
135
|
+
* Keeps the information about node elements position
|
136
|
+
* in the memory and its IDs/ordinals for export to the file
|
137
|
+
*/
|
138
|
+
typedef struct {
|
139
|
+
VALUE vals; // values: key=>val Hash
|
140
|
+
VALUE ids; // identifiers: key=>id Hash
|
141
|
+
VALUE pos; // free identifier
|
142
|
+
} LeafTableInfo;
|
143
|
+
|
144
|
+
void LeafTableInfo_init(LeafTableInfo *lti)
|
145
|
+
{
|
146
|
+
lti->vals = rb_hash_new();
|
147
|
+
lti->ids = rb_hash_new();
|
148
|
+
lti->pos = 0;
|
149
|
+
}
|
150
|
+
|
151
|
+
void LeafTableInfo_mark(LeafTableInfo *lti)
|
152
|
+
{
|
153
|
+
rb_gc_mark(lti->vals);
|
154
|
+
rb_gc_mark(lti->ids);
|
155
|
+
}
|
156
|
+
|
157
|
+
|
158
|
+
int LeafTableInfo_addEntry(LeafTableInfo *lti, VALUE key, VALUE value)
|
159
|
+
{
|
160
|
+
VALUE v_id = rb_hash_aref(lti->ids, key);
|
161
|
+
if (v_id == Qnil)
|
162
|
+
{
|
163
|
+
int id = lti->pos++;
|
164
|
+
rb_hash_aset(lti->vals, key, value);
|
165
|
+
rb_hash_aset(lti->ids, key, INT2FIX(id));
|
166
|
+
return id;
|
167
|
+
}
|
168
|
+
else
|
169
|
+
{
|
170
|
+
return FIX2INT(v_id);
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
VALUE LeafTableInfo_getLeavesTable(LeafTableInfo *lti)
|
175
|
+
{
|
176
|
+
VALUE key, keys = rb_funcall(lti->vals, rb_intern("keys"), 0);
|
177
|
+
unsigned int i;
|
178
|
+
VALUE val;
|
179
|
+
for (i = 0; i < lti->pos; i++)
|
180
|
+
{
|
181
|
+
key = RARRAY_PTR(keys)[i];
|
182
|
+
val = rb_hash_aref(lti->vals, key);
|
183
|
+
rb_ary_store(keys, i, val);
|
184
|
+
}
|
185
|
+
return keys;
|
186
|
+
}
|
187
|
+
|
188
|
+
int LeafTableInfo_keyToID(LeafTableInfo *lti, VALUE key)
|
189
|
+
{
|
190
|
+
VALUE id = rb_hash_aref(lti->ids, key);
|
191
|
+
return (id == Qnil) ? -1 : FIX2INT(id);
|
192
|
+
}
|
193
|
+
|
194
|
+
/* The structure keeps information about the node
|
195
|
+
that is required for its dumping to the file
|
196
|
+
(mainly hashes with relocatable identifiers) */
|
197
|
+
typedef struct {
|
198
|
+
LeafTableInfo syms; // Node symbols
|
199
|
+
LeafTableInfo lits; // Node literals
|
200
|
+
LeafTableInfo idtabs; // Table of identifiers
|
201
|
+
#ifdef USE_RB_ARGS_INFO
|
202
|
+
LeafTableInfo args; // Table of arguments
|
203
|
+
#endif
|
204
|
+
LeafTableInfo gentries; // Global variables table
|
205
|
+
LeafTableInfo nodes; // Table of nodes
|
206
|
+
} NODEInfo;
|
207
|
+
|
208
|
+
void NODEInfo_init(NODEInfo *info)
|
209
|
+
{
|
210
|
+
LeafTableInfo_init(&(info->syms));
|
211
|
+
LeafTableInfo_init(&(info->lits));
|
212
|
+
LeafTableInfo_init(&(info->idtabs));
|
213
|
+
#ifdef USE_RB_ARGS_INFO
|
214
|
+
LeafTableInfo_init(&(info->args));
|
215
|
+
#endif
|
216
|
+
LeafTableInfo_init(&(info->gentries));
|
217
|
+
LeafTableInfo_init(&(info->nodes));
|
218
|
+
}
|
219
|
+
|
220
|
+
void NODEInfo_mark(NODEInfo *info)
|
221
|
+
{
|
222
|
+
LeafTableInfo_mark(&(info->syms));
|
223
|
+
LeafTableInfo_mark(&(info->lits));
|
224
|
+
LeafTableInfo_mark(&(info->idtabs));
|
225
|
+
#ifdef USE_RB_ARGS_INFO
|
226
|
+
LeafTableInfo_mark(&(info->args));
|
227
|
+
#endif
|
228
|
+
LeafTableInfo_mark(&(info->gentries));
|
229
|
+
LeafTableInfo_mark(&(info->nodes));
|
230
|
+
}
|
231
|
+
|
232
|
+
void NODEInfo_free(NODEInfo *info)
|
233
|
+
{
|
234
|
+
xfree(info);
|
235
|
+
}
|
236
|
+
|
237
|
+
LeafTableInfo *NODEInfo_getTableByID(NODEInfo *info, int id)
|
238
|
+
{
|
239
|
+
switch (id)
|
240
|
+
{
|
241
|
+
case NT_ID:
|
242
|
+
return &info->syms;
|
243
|
+
case NT_VALUE:
|
244
|
+
return &info->lits;
|
245
|
+
case NT_IDTABLE:
|
246
|
+
return &info->idtabs;
|
247
|
+
#ifdef USE_RB_ARGS_INFO
|
248
|
+
case NT_ARGS:
|
249
|
+
return &info->args;
|
250
|
+
#endif
|
251
|
+
case NT_ENTRY:
|
252
|
+
return &info->gentries;
|
253
|
+
case NT_NODE:
|
254
|
+
return &info->nodes;
|
255
|
+
default:
|
256
|
+
return NULL;
|
257
|
+
}
|
258
|
+
}
|
259
|
+
|
260
|
+
/*
|
261
|
+
* Converts node value to the binary data
|
262
|
+
* Input parameters:
|
263
|
+
* info -- current NODEInfo structure
|
264
|
+
* node -- parent node (that contains the value)
|
265
|
+
* ptr -- pointer to the output memory buffer
|
266
|
+
* type -- type of the entry (NT_...)
|
267
|
+
* value -- node->u?.value VALUE
|
268
|
+
* child_id -- child node number (1,2,3)
|
269
|
+
* Returns:
|
270
|
+
* Byte that contains the next information
|
271
|
+
* a) upper half-byte: VL_... data type (for node loader)
|
272
|
+
* b) lower half-byte: number of bytes written to the buffer
|
273
|
+
*/
|
274
|
+
#define DUMP_RAW_VALUE(vl_ans, vl) (vl_ans | (value_to_bin(vl, (unsigned char *) ptr) << 4))
|
275
|
+
static int dump_node_value(NODEInfo *info, char *ptr, NODE *node, int type, VALUE value, int child_id)
|
276
|
+
{
|
277
|
+
if (type == NT_NULL || type == NT_LONG)
|
278
|
+
{
|
279
|
+
return DUMP_RAW_VALUE(VL_RAW, value);
|
280
|
+
}
|
281
|
+
else if (type == NT_NODE)
|
282
|
+
{
|
283
|
+
if (value == 0)
|
284
|
+
{ // Variant a: empty node
|
285
|
+
return DUMP_RAW_VALUE(VL_RAW, value);
|
286
|
+
}
|
287
|
+
else if (nd_type(node) == NODE_ATTRASGN && value == 1 && child_id == 1)
|
288
|
+
{ // Special case: "self"
|
289
|
+
return DUMP_RAW_VALUE(VL_RAW, value);
|
290
|
+
}
|
291
|
+
else if (TYPE(value) != T_NODE)
|
292
|
+
{
|
293
|
+
rb_raise(rb_eArgError, "dump_node_value, parent node %s: child node %d (ADR 0x%s): is not a node\n"
|
294
|
+
" Type: %s (%d), Value: %s",
|
295
|
+
ruby_node_name(nd_type(node)), child_id, RSTRING_PTR(value_to_str(value)),
|
296
|
+
RSTRING_PTR(rb_funcall(rb_funcall(value, rb_intern("class"), 0), rb_intern("to_s"), 0)),
|
297
|
+
TYPE(value),
|
298
|
+
RSTRING_PTR(rb_funcall(value, rb_intern("to_s"), 0)) );
|
299
|
+
}
|
300
|
+
else
|
301
|
+
{ // Variant b: not empty node
|
302
|
+
VALUE id = LeafTableInfo_keyToID(&info->nodes, value_to_str(value));
|
303
|
+
if (id == (VALUE) -1)
|
304
|
+
{
|
305
|
+
rb_raise(rb_eArgError, "dump_node_value, parent node %s: child node %d (ADR 0x%s) not found",
|
306
|
+
ruby_node_name(nd_type(node)), child_id, RSTRING_PTR(value_to_str(value)));
|
307
|
+
return VL_RAW;
|
308
|
+
}
|
309
|
+
else
|
310
|
+
{
|
311
|
+
return DUMP_RAW_VALUE(VL_NODE, id);
|
312
|
+
}
|
313
|
+
return VL_NODE;
|
314
|
+
}
|
315
|
+
}
|
316
|
+
else if (type == NT_VALUE)
|
317
|
+
{
|
318
|
+
if (!is_value_in_heap(value))
|
319
|
+
{ // a) value that is inside VALUE
|
320
|
+
return DUMP_RAW_VALUE(VL_RAW, value);
|
321
|
+
}
|
322
|
+
else
|
323
|
+
{ // b) value that requires reference to literals table
|
324
|
+
VALUE id = LeafTableInfo_keyToID(&info->lits, value_to_str(value));
|
325
|
+
if (id == (VALUE) -1)
|
326
|
+
rb_raise(rb_eArgError, "Cannot find literal");
|
327
|
+
else
|
328
|
+
return DUMP_RAW_VALUE(VL_LIT, id);
|
329
|
+
}
|
330
|
+
}
|
331
|
+
else if (type == NT_ID)
|
332
|
+
{
|
333
|
+
ID sym = (VALUE) value; // We are working with RAW data from RAM!
|
334
|
+
VALUE id = LeafTableInfo_keyToID(&info->syms, INT2FIX(sym));
|
335
|
+
if (id == (VALUE) -1)
|
336
|
+
{
|
337
|
+
rb_raise(rb_eArgError, "Cannot find symbol ID %d (%s) (parent node %s, line %d)",
|
338
|
+
(int) sym, RSTRING_PTR(rb_id2str(ID2SYM(sym))),
|
339
|
+
ruby_node_name(nd_type(node)), nd_line(node));
|
340
|
+
return VL_RAW;
|
341
|
+
}
|
342
|
+
else
|
343
|
+
{
|
344
|
+
return DUMP_RAW_VALUE(VL_ID, id);
|
345
|
+
}
|
346
|
+
}
|
347
|
+
else if (type == NT_ENTRY || type == NT_ARGS || type == NT_IDTABLE)
|
348
|
+
{
|
349
|
+
VALUE key = value_to_str(value);
|
350
|
+
LeafTableInfo *lti = NODEInfo_getTableByID(info, type);
|
351
|
+
VALUE id = LeafTableInfo_keyToID(lti, key);
|
352
|
+
if (id == (VALUE) -1)
|
353
|
+
{
|
354
|
+
rb_raise(rb_eArgError, "Cannot find some entry");
|
355
|
+
return VL_RAW;
|
356
|
+
}
|
357
|
+
else
|
358
|
+
{
|
359
|
+
//memcpy(ptr, &id, sizeof(VALUE));
|
360
|
+
switch(type)
|
361
|
+
{
|
362
|
+
case NT_ENTRY: return DUMP_RAW_VALUE(VL_GVAR, id);
|
363
|
+
case NT_IDTABLE: return DUMP_RAW_VALUE(VL_IDTABLE, id);
|
364
|
+
case NT_ARGS: return DUMP_RAW_VALUE(VL_ARGS, id);
|
365
|
+
default: rb_raise(rb_eArgError, "Internal error");
|
366
|
+
}
|
367
|
+
}
|
368
|
+
}
|
369
|
+
else
|
370
|
+
{
|
371
|
+
rb_raise(rb_eArgError, "Unknown child node type %d", type);
|
372
|
+
}
|
373
|
+
}
|
374
|
+
|
375
|
+
static VALUE dump_nodes(NODEInfo *info)
|
376
|
+
{
|
377
|
+
int node_size = sizeof(int) + sizeof(VALUE) * 4;
|
378
|
+
int i, nt, flags_len;
|
379
|
+
NODE *node;
|
380
|
+
char *bin, *ptr, *rtypes;
|
381
|
+
VALUE nodes_ary = rb_funcall(info->nodes.vals, rb_intern("keys"), 0);
|
382
|
+
VALUE nodes_bin = rb_str_new(NULL, RARRAY_LEN(nodes_ary) * node_size);
|
383
|
+
VALUE ut[3];
|
384
|
+
bin = RSTRING_PTR(nodes_bin);
|
385
|
+
|
386
|
+
for (i = 0, ptr = bin; i < RARRAY_LEN(nodes_ary); i++)
|
387
|
+
{
|
388
|
+
node = RNODE(str_to_value(RARRAY_PTR(nodes_ary)[i]));
|
389
|
+
nt = nd_type(node);
|
390
|
+
rtypes = (char *) ptr; ptr += sizeof(int);
|
391
|
+
flags_len = value_to_bin(node->flags >> 5, (unsigned char *) ptr); ptr += flags_len;
|
392
|
+
//memcpy(ptr, &(node->flags), sizeof(VALUE)); ptr += sizeof(VALUE);
|
393
|
+
ut[0] = nodes_ctbl[nt * 3];
|
394
|
+
ut[1] = nodes_ctbl[nt * 3 + 1];
|
395
|
+
ut[2] = nodes_ctbl[nt * 3 + 2];
|
396
|
+
if (nt == NODE_OP_ASGN2 && LeafTableInfo_keyToID(&info->syms, INT2FIX(node->u1.value)) != -1)
|
397
|
+
{
|
398
|
+
ut[0] = NT_ID; ut[1] = NT_ID; ut[2] = NT_ID;
|
399
|
+
}
|
400
|
+
|
401
|
+
if (nt == NODE_ARGS_AUX)
|
402
|
+
{
|
403
|
+
ut[0] = NT_ID; ut[1] = NT_LONG; ut[2] = NT_NODE;
|
404
|
+
if (LeafTableInfo_keyToID(&info->syms, INT2FIX(node->u2.value)) != -1)
|
405
|
+
{
|
406
|
+
ut[1] = NT_ID;
|
407
|
+
}
|
408
|
+
else
|
409
|
+
{
|
410
|
+
ut[1] = NT_LONG;
|
411
|
+
}
|
412
|
+
if (node->u1.value == 0) ut[0] = NT_NULL;
|
413
|
+
if (node->u2.value == 0) ut[1] = NT_NULL;
|
414
|
+
if (node->u3.value == 0) ut[2] = NT_NULL;
|
415
|
+
}
|
416
|
+
|
417
|
+
rtypes[0] = dump_node_value(info, ptr, node, ut[0], node->u1.value, 1);
|
418
|
+
ptr += (rtypes[0] & 0xF0) >> 4;
|
419
|
+
rtypes[1] = dump_node_value(info, ptr, node, ut[1], node->u2.value, 2);
|
420
|
+
ptr += (rtypes[1] & 0xF0) >> 4;
|
421
|
+
rtypes[2] = dump_node_value(info, ptr, node, ut[2], node->u3.value, 3);
|
422
|
+
ptr += (rtypes[2] & 0xF0) >> 4;
|
423
|
+
rtypes[3] = flags_len;
|
424
|
+
}
|
425
|
+
rb_str_resize(nodes_bin, (int) (ptr - bin) + 1);
|
426
|
+
//printf("%d", ptr - bin);
|
427
|
+
return nodes_bin;
|
428
|
+
}
|
429
|
+
|
430
|
+
|
431
|
+
/*
|
432
|
+
* Transforms preprocessed node to Ruby hash that can be used
|
433
|
+
* to load the node from disk.
|
434
|
+
*
|
435
|
+
* See m_nodedump_to_hash function for output hash format details
|
436
|
+
*/
|
437
|
+
VALUE NODEInfo_toHash(NODEInfo *info)
|
438
|
+
{
|
439
|
+
VALUE ans = rb_hash_new();
|
440
|
+
VALUE idtbl, idtabs = LeafTableInfo_getLeavesTable(&info->idtabs);
|
441
|
+
VALUE syms = LeafTableInfo_getLeavesTable(&info->syms);
|
442
|
+
VALUE args;
|
443
|
+
int i, j, id;
|
444
|
+
// Add some signatures
|
445
|
+
rb_hash_aset(ans, ID2SYM(rb_intern("MAGIC")), rb_str_new2("NODEMARSHAL10"));
|
446
|
+
rb_hash_aset(ans, ID2SYM(rb_intern("RUBY_PLATFORM")),
|
447
|
+
rb_const_get(rb_cObject, rb_intern("RUBY_PLATFORM")));
|
448
|
+
rb_hash_aset(ans, ID2SYM(rb_intern("RUBY_VERSION")),
|
449
|
+
rb_const_get(rb_cObject, rb_intern("RUBY_VERSION")));
|
450
|
+
// Write literals, symbols and global_entries arrays: they don't need to be corrected
|
451
|
+
rb_hash_aset(ans, ID2SYM(rb_intern("literals")), LeafTableInfo_getLeavesTable(&info->lits));
|
452
|
+
rb_hash_aset(ans, ID2SYM(rb_intern("symbols")), syms);
|
453
|
+
rb_hash_aset(ans, ID2SYM(rb_intern("global_entries")), LeafTableInfo_getLeavesTable(&info->gentries));
|
454
|
+
// Replace RAM IDs to disk IDs in id_tables
|
455
|
+
for (i = 0; i < RARRAY_LEN(idtabs); i++)
|
456
|
+
{
|
457
|
+
idtbl = RARRAY_PTR(idtabs)[i];
|
458
|
+
for (j = 0; j < RARRAY_LEN(idtbl); j++)
|
459
|
+
{
|
460
|
+
id = LeafTableInfo_keyToID(&info->syms, RARRAY_PTR(idtbl)[j]);
|
461
|
+
|
462
|
+
if (id == -1)
|
463
|
+
{
|
464
|
+
ID sym = FIX2INT(RARRAY_PTR(idtbl)[j]);
|
465
|
+
rb_raise(rb_eArgError, "Cannot find the symbol ID %d", (int) sym);
|
466
|
+
}
|
467
|
+
else
|
468
|
+
{
|
469
|
+
rb_ary_store(idtbl, j, INT2FIX(id));
|
470
|
+
}
|
471
|
+
|
472
|
+
}
|
473
|
+
}
|
474
|
+
rb_hash_aset(ans, ID2SYM(rb_intern("id_tables")), idtabs);
|
475
|
+
// Replace RAM IDs to disk IDs in args tables
|
476
|
+
#ifdef USE_RB_ARGS_INFO
|
477
|
+
args = LeafTableInfo_getLeavesTable(&info->args);
|
478
|
+
for (i = 0; i < RARRAY_LEN(args); i++)
|
479
|
+
{
|
480
|
+
VALUE args_entry = RARRAY_PTR(args)[i];
|
481
|
+
VALUE *eptr = RARRAY_PTR(args_entry);
|
482
|
+
int args_vals[5] = {0, 1, 7, 8, 9};
|
483
|
+
int args_ids[3] = {4, 5, 6};
|
484
|
+
if (RARRAY_LEN(args_entry) != 10)
|
485
|
+
rb_raise(rb_eArgError, "Corrupted args entry");
|
486
|
+
// Pointer to nodes to be replaced:
|
487
|
+
// a) VALUES
|
488
|
+
// (0) pre_init, (1) post_init,
|
489
|
+
// (7) kw_args, (8) kw_rest_arg, (9) opt_args
|
490
|
+
for (j = 0; j < 5; j++)
|
491
|
+
{
|
492
|
+
int ind = args_vals[j];
|
493
|
+
VALUE key = eptr[ind];
|
494
|
+
if (!strcmp(RSTRING_PTR(key), "0"))
|
495
|
+
eptr[ind] = INT2FIX(-1);
|
496
|
+
else
|
497
|
+
{
|
498
|
+
eptr[ind] = INT2FIX(LeafTableInfo_keyToID(&info->nodes, key));
|
499
|
+
if (FIX2INT(eptr[ind]) == -1)
|
500
|
+
rb_raise(rb_eArgError, "Unknown NODE in args tables");
|
501
|
+
}
|
502
|
+
}
|
503
|
+
// b) IDs (symbols)
|
504
|
+
// (4) first_post_arg (5) rest_arg (6) block_arg
|
505
|
+
for (j = 0; j < 3; j++)
|
506
|
+
{
|
507
|
+
int ind = args_ids[j];
|
508
|
+
VALUE key = eptr[ind];
|
509
|
+
if (FIX2INT(key) != 0)
|
510
|
+
{
|
511
|
+
eptr[ind] = INT2FIX(LeafTableInfo_keyToID(&info->syms, key));
|
512
|
+
if (FIX2INT(eptr[ind]) == -1)
|
513
|
+
rb_raise(rb_eArgError, "Unknown symbolic ID in args tables");
|
514
|
+
}
|
515
|
+
else
|
516
|
+
eptr[ind] = INT2FIX(-1);
|
517
|
+
}
|
518
|
+
}
|
519
|
+
#else
|
520
|
+
args = rb_ary_new();
|
521
|
+
#endif
|
522
|
+
|
523
|
+
rb_hash_aset(ans, ID2SYM(rb_intern("args")), args);
|
524
|
+
// Special case: NODES. Nodes are kept as binary string
|
525
|
+
rb_hash_aset(ans, ID2SYM(rb_intern("nodes")), dump_nodes(info));
|
526
|
+
return ans;
|
527
|
+
}
|
528
|
+
|
529
|
+
|
530
|
+
static void NODEInfo_addValue(NODEInfo *info, VALUE value)
|
531
|
+
{
|
532
|
+
if (is_value_in_heap(value))
|
533
|
+
{
|
534
|
+
VALUE lkey = value_to_str(value);
|
535
|
+
LeafTableInfo_addEntry(&info->lits, lkey, value);
|
536
|
+
}
|
537
|
+
}
|
538
|
+
|
539
|
+
/*
|
540
|
+
* Function counts number of nodes and fills NODEInfo struct
|
541
|
+
* that is neccessary for the node saving to the HDD
|
542
|
+
*/
|
543
|
+
int count_num_of_nodes(NODE *node, NODE *parent, NODEInfo *info)
|
544
|
+
{
|
545
|
+
int ut[3], num, offset;
|
546
|
+
if (node == 0)
|
547
|
+
{
|
548
|
+
return 0;
|
549
|
+
}
|
550
|
+
else if (TYPE((VALUE) node) != T_NODE)
|
551
|
+
{
|
552
|
+
rb_raise(rb_eArgError, "count_num_of_nodes: parent node %s: child node (ADR 0x%s) is not a node; Type: %d",
|
553
|
+
ruby_node_name(nd_type(parent)), RSTRING_PTR(value_to_str((VALUE) node)), TYPE((VALUE) node));
|
554
|
+
return 0;
|
555
|
+
}
|
556
|
+
else
|
557
|
+
{
|
558
|
+
offset = nd_type(node) * 3;
|
559
|
+
ut[0] = nodes_ctbl[offset++];
|
560
|
+
ut[1] = nodes_ctbl[offset++];
|
561
|
+
ut[2] = nodes_ctbl[offset];
|
562
|
+
|
563
|
+
if (nd_type(node) == NODE_OP_ASGN2 && nd_type(parent) == NODE_OP_ASGN2)
|
564
|
+
{
|
565
|
+
ut[0] = NT_ID;
|
566
|
+
ut[1] = NT_ID;
|
567
|
+
ut[2] = NT_ID;
|
568
|
+
}
|
569
|
+
|
570
|
+
/* Some Ruby 1.9.3 style function arguments (without rb_args_info) */
|
571
|
+
if (nd_type(node) == NODE_ARGS_AUX)
|
572
|
+
{
|
573
|
+
ut[0] = NT_ID;
|
574
|
+
ut[1] = (nd_type(parent) == NODE_ARGS_AUX) ? NT_LONG : NT_ID;
|
575
|
+
ut[2] = NT_NODE;
|
576
|
+
|
577
|
+
if (node->u1.value == 0) ut[0] = NT_NULL;
|
578
|
+
if (node->u2.value == 0) ut[1] = NT_NULL;
|
579
|
+
if (node->u3.value == 0) ut[2] = NT_NULL;
|
580
|
+
}
|
581
|
+
/* Some Ruby 1.9.3-specific code for NODE_ATTRASGN */
|
582
|
+
if (nd_type(node) == NODE_ATTRASGN)
|
583
|
+
{
|
584
|
+
if (node->u1.value == 1) ut[0] = NT_LONG;
|
585
|
+
}
|
586
|
+
/* Check if there is information about child nodes types */
|
587
|
+
if (ut[0] == NT_UNKNOWN || ut[1] == NT_UNKNOWN || ut[2] == NT_UNKNOWN)
|
588
|
+
{
|
589
|
+
rb_raise(rb_eArgError, "Cannot interpret node %d (%s)", nd_type(node), ruby_node_name(nd_type(node)));
|
590
|
+
}
|
591
|
+
/* Save the ID of the node */
|
592
|
+
num = 1;
|
593
|
+
LeafTableInfo_addEntry(&info->nodes, value_to_str((VALUE) node), value_to_str((VALUE) node));
|
594
|
+
/* Analyze node childs */
|
595
|
+
/* a) child 1 */
|
596
|
+
if (ut[0] == NT_NODE)
|
597
|
+
{
|
598
|
+
num += count_num_of_nodes(node->u1.node, node, info);
|
599
|
+
}
|
600
|
+
else if (ut[0] == NT_ID)
|
601
|
+
{
|
602
|
+
LeafTableInfo_addEntry(&info->syms, INT2FIX(node->u1.id), rb_id2str(node->u1.id));
|
603
|
+
}
|
604
|
+
else if (ut[0] == NT_VALUE)
|
605
|
+
{
|
606
|
+
if (TYPE(node->u1.value) == T_NODE)
|
607
|
+
rb_raise(rb_eArgError, "NODE instead of VALUE in child 1 of node %s", ruby_node_name(nd_type(node)));
|
608
|
+
NODEInfo_addValue(info, node->u1.value);
|
609
|
+
}
|
610
|
+
else if (ut[0] == NT_IDTABLE)
|
611
|
+
{
|
612
|
+
VALUE tkey = value_to_str(node->u1.value);
|
613
|
+
VALUE idtbl_ary = rb_ary_new();
|
614
|
+
ID *idtbl = (ID *) node->u1.value;
|
615
|
+
int i, size = (node->u1.value) ? *idtbl++ : 0;
|
616
|
+
for (i = 0; i < size; i++)
|
617
|
+
{
|
618
|
+
ID sym = *idtbl++;
|
619
|
+
rb_ary_push(idtbl_ary, INT2FIX(sym));
|
620
|
+
LeafTableInfo_addEntry(&info->syms, INT2FIX(sym), rb_id2str(sym));
|
621
|
+
}
|
622
|
+
LeafTableInfo_addEntry(&info->idtabs, tkey, idtbl_ary);
|
623
|
+
}
|
624
|
+
else if (ut[0] != NT_LONG && ut[0] != NT_NULL)
|
625
|
+
{
|
626
|
+
rb_raise(rb_eArgError, "1!");
|
627
|
+
}
|
628
|
+
/* b) child 2 */
|
629
|
+
if (ut[1] == NT_NODE)
|
630
|
+
{
|
631
|
+
num += count_num_of_nodes(node->u2.node, node, info);
|
632
|
+
}
|
633
|
+
else if (ut[1] == NT_ID)
|
634
|
+
{
|
635
|
+
LeafTableInfo_addEntry(&info->syms, INT2FIX(node->u2.id), rb_id2str(node->u2.id));
|
636
|
+
}
|
637
|
+
else if (ut[1] == NT_VALUE)
|
638
|
+
{
|
639
|
+
if (TYPE(node->u2.value) == T_NODE)
|
640
|
+
rb_raise(rb_eArgError, "NODE instead of VALUE in child 2 of node %s", ruby_node_name(nd_type(node)));
|
641
|
+
NODEInfo_addValue(info, node->u2.value);
|
642
|
+
}
|
643
|
+
else if (ut[1] != NT_LONG && ut[1] != NT_NULL)
|
644
|
+
{
|
645
|
+
rb_raise(rb_eArgError, "2!");
|
646
|
+
}
|
647
|
+
|
648
|
+
/* c) child 3 */
|
649
|
+
if (ut[2] == NT_NODE)
|
650
|
+
{
|
651
|
+
num += count_num_of_nodes(node->u3.node, node, info);
|
652
|
+
}
|
653
|
+
else if (ut[2] == NT_ID)
|
654
|
+
{
|
655
|
+
LeafTableInfo_addEntry(&info->syms, INT2FIX(node->u3.id), rb_id2str(node->u3.id));
|
656
|
+
}
|
657
|
+
else if (ut[2] == NT_ARGS)
|
658
|
+
{
|
659
|
+
#ifdef USE_RB_ARGS_INFO
|
660
|
+
VALUE varg = Qtrue;
|
661
|
+
struct rb_args_info *ainfo;
|
662
|
+
ID asym;
|
663
|
+
ainfo = node->u3.args;
|
664
|
+
// Save child nodes
|
665
|
+
num += count_num_of_nodes(ainfo->pre_init, node, info);
|
666
|
+
num += count_num_of_nodes(ainfo->post_init, node, info);
|
667
|
+
num += count_num_of_nodes(ainfo->kw_args, node, info);
|
668
|
+
num += count_num_of_nodes(ainfo->kw_rest_arg, node, info);
|
669
|
+
num += count_num_of_nodes(ainfo->opt_args, node, info);
|
670
|
+
// Save rb_args_info structure content
|
671
|
+
varg = rb_ary_new();
|
672
|
+
rb_ary_push(varg, value_to_str((VALUE) ainfo->pre_init));
|
673
|
+
rb_ary_push(varg, value_to_str((VALUE) ainfo->post_init));
|
674
|
+
rb_ary_push(varg, INT2FIX(ainfo->pre_args_num));
|
675
|
+
rb_ary_push(varg, INT2FIX(ainfo->post_args_num));
|
676
|
+
|
677
|
+
asym = ainfo->first_post_arg; rb_ary_push(varg, INT2FIX(asym)); // ID
|
678
|
+
if (asym != 0)
|
679
|
+
LeafTableInfo_addEntry(&info->syms, INT2FIX(asym), rb_id2str(asym));
|
680
|
+
|
681
|
+
asym = ainfo->rest_arg; rb_ary_push(varg, INT2FIX(asym)); // ID
|
682
|
+
if (asym != 0)
|
683
|
+
LeafTableInfo_addEntry(&info->syms, INT2FIX(asym), rb_id2str(asym));
|
684
|
+
|
685
|
+
asym = ainfo->block_arg; rb_ary_push(varg, INT2FIX(asym)); // ID
|
686
|
+
if (asym != 0)
|
687
|
+
LeafTableInfo_addEntry(&info->syms, INT2FIX(asym), rb_id2str(asym));
|
688
|
+
rb_ary_push(varg, value_to_str((VALUE) ainfo->kw_args));
|
689
|
+
rb_ary_push(varg, value_to_str((VALUE) ainfo->kw_rest_arg));
|
690
|
+
rb_ary_push(varg, value_to_str((VALUE) ainfo->opt_args));
|
691
|
+
|
692
|
+
LeafTableInfo_addEntry(&info->args, value_to_str((VALUE) ainfo), varg);
|
693
|
+
#else
|
694
|
+
rb_raise(rb_eArgError, "NT_ARGS entry withour USE_RB_ARGS_INFO");
|
695
|
+
#endif
|
696
|
+
}
|
697
|
+
else if (ut[2] == NT_ENTRY)
|
698
|
+
{
|
699
|
+
ID gsym = node->u3.entry->id;
|
700
|
+
// Save symbol to the symbol table
|
701
|
+
int newid = LeafTableInfo_addEntry(&info->syms, INT2FIX(gsym), rb_id2str(gsym));
|
702
|
+
LeafTableInfo_addEntry(&info->gentries, value_to_str(node->u3.value), INT2FIX(newid));
|
703
|
+
}
|
704
|
+
else if (ut[2] != NT_LONG && ut[2] != NT_NULL)
|
705
|
+
{
|
706
|
+
rb_raise(rb_eArgError, "Invalid child node 3: %d", ut[2]);
|
707
|
+
}
|
708
|
+
|
709
|
+
return num;
|
710
|
+
}
|
711
|
+
}
|
712
|
+
|
713
|
+
|
714
|
+
|
715
|
+
//-------------------------------------------------------------------------
|
716
|
+
|
717
|
+
/*
|
718
|
+
* Part 4. Functions for loading marshalled nodes
|
719
|
+
*/
|
720
|
+
typedef struct {
|
721
|
+
ID *syms_adr; // Table of symbols
|
722
|
+
int syms_len;
|
723
|
+
|
724
|
+
VALUE *lits_adr; // Table of literals
|
725
|
+
int lits_len;
|
726
|
+
|
727
|
+
ID **idtbls_adr; // Table of symbols tables
|
728
|
+
int idtbls_len;
|
729
|
+
|
730
|
+
struct rb_global_entry **gvars_adr; // Table of global variables entries
|
731
|
+
int gvars_len;
|
732
|
+
|
733
|
+
NODE **nodes_adr; // Table of nodes
|
734
|
+
int nodes_len;
|
735
|
+
#ifdef USE_RB_ARGS_INFO
|
736
|
+
struct rb_args_info **args_adr; // Table of code blocks arguments
|
737
|
+
int args_len;
|
738
|
+
#endif
|
739
|
+
} NODEObjAddresses;
|
740
|
+
|
741
|
+
|
742
|
+
void NODEObjAddresses_free(NODEObjAddresses *obj)
|
743
|
+
{
|
744
|
+
xfree(obj->syms_adr);
|
745
|
+
xfree(obj->idtbls_adr);
|
746
|
+
xfree(obj->gvars_adr);
|
747
|
+
xfree(obj->nodes_adr);
|
748
|
+
#ifdef USE_RB_ARGS_INFO
|
749
|
+
xfree(obj->args_adr);
|
750
|
+
#endif
|
751
|
+
xfree(obj);
|
752
|
+
}
|
753
|
+
|
754
|
+
|
755
|
+
|
756
|
+
void rbstr_printf(VALUE str, const char *fmt, ...)
|
757
|
+
{
|
758
|
+
char buf[1024];
|
759
|
+
va_list ptr;
|
760
|
+
|
761
|
+
va_start(ptr, fmt);
|
762
|
+
vsprintf(buf, fmt, ptr);
|
763
|
+
rb_str_append(str, rb_str_new2(buf));
|
764
|
+
va_end(ptr);
|
765
|
+
}
|
766
|
+
|
767
|
+
#define PRINT_NODE_TAB for (j = 0; j < tab; j++) rbstr_printf(str, " ");
|
768
|
+
void print_node(VALUE str, NODE *node, int tab)
|
769
|
+
{
|
770
|
+
int i, j, type, ut[3];
|
771
|
+
int show_offsets = 0;
|
772
|
+
VALUE uref[3];
|
773
|
+
|
774
|
+
PRINT_NODE_TAB
|
775
|
+
if (node == NULL)
|
776
|
+
{
|
777
|
+
rbstr_printf(str, "(NULL)\n");
|
778
|
+
return;
|
779
|
+
}
|
780
|
+
type = nd_type(node);
|
781
|
+
|
782
|
+
if (show_offsets)
|
783
|
+
{
|
784
|
+
rbstr_printf(str, "@ %s | %16"PRIxPTR " %16"PRIxPTR " %16"PRIxPTR "\n", ruby_node_name(type),
|
785
|
+
(intptr_t) node->u1.value, (intptr_t) node->u2.value, (intptr_t) node->u3.value);
|
786
|
+
}
|
787
|
+
else
|
788
|
+
{
|
789
|
+
rbstr_printf(str, "@ %s\n", ruby_node_name(type));
|
790
|
+
}
|
791
|
+
|
792
|
+
ut[0] = nodes_ctbl[type * 3];
|
793
|
+
ut[1] = nodes_ctbl[type * 3 + 1];
|
794
|
+
ut[2] = nodes_ctbl[type * 3 + 2];
|
795
|
+
|
796
|
+
uref[0] = node->u1.value;
|
797
|
+
uref[1] = node->u2.value;
|
798
|
+
uref[2] = node->u3.value;
|
799
|
+
|
800
|
+
for (i = 0; i < 3; i++)
|
801
|
+
{
|
802
|
+
|
803
|
+
if (ut[i] == NT_NODE)
|
804
|
+
{
|
805
|
+
if (nd_type(node) != NODE_OP_ASGN2 || i != 2)
|
806
|
+
print_node(str, RNODE(uref[i]), tab + 1);
|
807
|
+
else
|
808
|
+
{
|
809
|
+
if (ut[i] != 0 && TYPE(ut[i]) != T_NODE)
|
810
|
+
rb_raise(rb_eArgError, "print_node: broken node 0x%s", RSTRING_PTR(value_to_str(ut[i])));
|
811
|
+
PRINT_NODE_TAB; rbstr_printf(str, " ");
|
812
|
+
rbstr_printf(str, "%"PRIxPTR " %"PRIxPTR " %"PRIxPTR"\n",
|
813
|
+
(intptr_t) RNODE(uref[i])->u1.value,
|
814
|
+
(intptr_t) RNODE(uref[i])->u2.value,
|
815
|
+
(intptr_t) RNODE(uref[i])->u3.value);
|
816
|
+
}
|
817
|
+
}
|
818
|
+
else if (ut[i] == NT_VALUE)
|
819
|
+
{
|
820
|
+
char *class_name = RSTRING_PTR(rb_funcall(rb_funcall(uref[i], rb_intern("class"), 0), rb_intern("to_s"), 0));
|
821
|
+
PRINT_NODE_TAB; rbstr_printf(str, " ");
|
822
|
+
if (show_offsets)
|
823
|
+
{
|
824
|
+
rbstr_printf(str, ">| ADR: %"PRIxPTR" TYPE: %d TEXT: %s\n",
|
825
|
+
(intptr_t) uref[i],
|
826
|
+
class_name, TYPE(uref[i]),
|
827
|
+
RSTRING_PTR(rb_funcall(uref[i], rb_intern("to_s"), 0)));
|
828
|
+
}
|
829
|
+
else
|
830
|
+
{
|
831
|
+
rbstr_printf(str, ">| CLASS: %s (TYPE %d); VALUE: %s\n",
|
832
|
+
class_name, TYPE(uref[i]),
|
833
|
+
RSTRING_PTR(rb_funcall(uref[i], rb_intern("to_s"), 0)));
|
834
|
+
}
|
835
|
+
}
|
836
|
+
else if (ut[i] == NT_ID)
|
837
|
+
{
|
838
|
+
PRINT_NODE_TAB; rbstr_printf(str, " ");
|
839
|
+
if (show_offsets)
|
840
|
+
rbstr_printf(str, ">| ID: %d; SYMBOL: %s\n", (ID) uref[i], RSTRING_PTR(rb_id2str(uref[i])));
|
841
|
+
else
|
842
|
+
rbstr_printf(str, ">| SYMBOL: :%s\n", RSTRING_PTR(rb_id2str(uref[i])));
|
843
|
+
}
|
844
|
+
else if (ut[i] == NT_LONG)
|
845
|
+
{
|
846
|
+
PRINT_NODE_TAB; rbstr_printf(str, " ");
|
847
|
+
rbstr_printf(str, ">| %"PRIxPTR "\n", (intptr_t) uref[i]);
|
848
|
+
}
|
849
|
+
else if (ut[i] == NT_NULL)
|
850
|
+
{
|
851
|
+
PRINT_NODE_TAB; rbstr_printf(str, " ");
|
852
|
+
rbstr_printf(str, ">| (NULL)\n");
|
853
|
+
}
|
854
|
+
else if (ut[i] == NT_ARGS)
|
855
|
+
{
|
856
|
+
PRINT_NODE_TAB; rbstr_printf(str, " ");
|
857
|
+
rbstr_printf(str, ">| ARGS\n");
|
858
|
+
}
|
859
|
+
else if (ut[i] == NT_IDTABLE)
|
860
|
+
{
|
861
|
+
PRINT_NODE_TAB; rbstr_printf(str, " ");
|
862
|
+
rbstr_printf(str, ">| IDTABLE\n");
|
863
|
+
}
|
864
|
+
else
|
865
|
+
{
|
866
|
+
PRINT_NODE_TAB; rbstr_printf(str, " ");
|
867
|
+
rbstr_printf(str, ">| [UNKNOWN]\n");
|
868
|
+
}
|
869
|
+
}
|
870
|
+
}
|
871
|
+
|
872
|
+
|
873
|
+
|
874
|
+
void resolve_syms_ords(VALUE data, NODEObjAddresses *relocs)
|
875
|
+
{
|
876
|
+
VALUE tbl_val = rb_hash_aref(data, ID2SYM(rb_intern("symbols")));
|
877
|
+
int i;
|
878
|
+
if (tbl_val == Qnil)
|
879
|
+
{
|
880
|
+
rb_raise(rb_eArgError, "Cannot find symbols table");
|
881
|
+
}
|
882
|
+
if (TYPE(tbl_val) != T_ARRAY)
|
883
|
+
{
|
884
|
+
rb_raise(rb_eArgError, "Symbols table is not an array");
|
885
|
+
}
|
886
|
+
relocs->syms_len = RARRAY_LEN(tbl_val);
|
887
|
+
relocs->syms_adr = ALLOC_N(ID, relocs->syms_len);
|
888
|
+
for (i = 0; i < relocs->syms_len; i++)
|
889
|
+
relocs->syms_adr[i] = rb_intern(RSTRING_PTR(RARRAY_PTR(tbl_val)[i]));
|
890
|
+
}
|
891
|
+
|
892
|
+
void resolve_lits_ords(VALUE data, NODEObjAddresses *relocs)
|
893
|
+
{
|
894
|
+
VALUE tbl_val = rb_hash_aref(data, ID2SYM(rb_intern("literals")));
|
895
|
+
if (tbl_val == Qnil)
|
896
|
+
{
|
897
|
+
rb_raise(rb_eArgError, "Cannot find literals table");
|
898
|
+
}
|
899
|
+
if (TYPE(tbl_val) != T_ARRAY)
|
900
|
+
{
|
901
|
+
rb_raise(rb_eArgError, "Literals table is not an array");
|
902
|
+
}
|
903
|
+
relocs->lits_adr = RARRAY_PTR(tbl_val);
|
904
|
+
relocs->lits_len = RARRAY_LEN(tbl_val);
|
905
|
+
}
|
906
|
+
|
907
|
+
void resolve_gvars_ords(VALUE data, NODEObjAddresses *relocs)
|
908
|
+
{
|
909
|
+
VALUE tbl_val = rb_hash_aref(data, ID2SYM(rb_intern("global_entries")));
|
910
|
+
int i;
|
911
|
+
|
912
|
+
if (tbl_val == Qnil)
|
913
|
+
{
|
914
|
+
rb_raise(rb_eArgError, "Cannot find global entries table");
|
915
|
+
}
|
916
|
+
if (TYPE(tbl_val) != T_ARRAY)
|
917
|
+
{
|
918
|
+
rb_raise(rb_eArgError, "Global entries table should be an array");
|
919
|
+
}
|
920
|
+
relocs->gvars_len = RARRAY_LEN(tbl_val);
|
921
|
+
relocs->gvars_adr = ALLOC_N(struct rb_global_entry *, relocs->gvars_len);
|
922
|
+
for (i = 0; i < relocs->gvars_len; i++)
|
923
|
+
{
|
924
|
+
int ind = FIX2INT(RARRAY_PTR(tbl_val)[i]);
|
925
|
+
ID sym = relocs->syms_adr[ind];
|
926
|
+
relocs->gvars_adr[i] = rb_global_entry(sym);
|
927
|
+
}
|
928
|
+
}
|
929
|
+
|
930
|
+
|
931
|
+
void resolve_idtbls_ords(VALUE data, NODEObjAddresses *relocs)
|
932
|
+
{
|
933
|
+
VALUE tbl_val = rb_hash_aref(data, ID2SYM(rb_intern("id_tables")));
|
934
|
+
int i, j, idnum;
|
935
|
+
|
936
|
+
if (tbl_val == Qnil)
|
937
|
+
{
|
938
|
+
rb_raise(rb_eArgError, "Cannot find id_tables entries");
|
939
|
+
}
|
940
|
+
relocs->idtbls_len = RARRAY_LEN(tbl_val);
|
941
|
+
relocs->idtbls_adr = ALLOC_N(ID *, relocs->idtbls_len);
|
942
|
+
for (i = 0; i < relocs->idtbls_len; i++)
|
943
|
+
{
|
944
|
+
VALUE idtbl = RARRAY_PTR(tbl_val)[i];
|
945
|
+
idnum = RARRAY_LEN(idtbl);
|
946
|
+
if (idnum == 0)
|
947
|
+
{ // Empty table: NULL pointer in the address table
|
948
|
+
relocs->idtbls_adr[i] = NULL;
|
949
|
+
}
|
950
|
+
else
|
951
|
+
{ // Filled table: pointer to dynamic memory
|
952
|
+
relocs->idtbls_adr[i] = ALLOC_N(ID, idnum + 1);
|
953
|
+
relocs->idtbls_adr[i][0] = idnum;
|
954
|
+
for (j = 0; j < idnum; j++)
|
955
|
+
{
|
956
|
+
int ind = FIX2INT(RARRAY_PTR(idtbl)[j]);
|
957
|
+
relocs->idtbls_adr[i][j+1] = relocs->syms_adr[ind];
|
958
|
+
}
|
959
|
+
}
|
960
|
+
}
|
961
|
+
}
|
962
|
+
|
963
|
+
void resolve_nodes_ords(VALUE data, int num_of_nodes, NODEObjAddresses *relocs)
|
964
|
+
{
|
965
|
+
int i;
|
966
|
+
VALUE tbl_val = rb_hash_aref(data, ID2SYM(rb_intern("nodes")));
|
967
|
+
if (tbl_val == Qnil)
|
968
|
+
{
|
969
|
+
rb_raise(rb_eArgError, "Cannot find nodes entries");
|
970
|
+
}
|
971
|
+
if (TYPE(tbl_val) != T_STRING)
|
972
|
+
{
|
973
|
+
rb_raise(rb_eArgError, "Nodes description must be a string");
|
974
|
+
}
|
975
|
+
relocs->nodes_adr = ALLOC_N(NODE *, num_of_nodes);
|
976
|
+
relocs->nodes_len = num_of_nodes;
|
977
|
+
for (i = 0; i < num_of_nodes; i++)
|
978
|
+
{
|
979
|
+
relocs->nodes_adr[i] = (NODE *) NEW_NODE((enum node_type) 0, 0, 0, 0);
|
980
|
+
}
|
981
|
+
}
|
982
|
+
|
983
|
+
#ifdef USE_RB_ARGS_INFO
|
984
|
+
void resolve_args_ords(VALUE data, NODEObjAddresses *relocs)
|
985
|
+
{
|
986
|
+
int i;
|
987
|
+
VALUE tbl_val = rb_hash_aref(data, ID2SYM(rb_intern("args")));
|
988
|
+
|
989
|
+
if (tbl_val == Qnil)
|
990
|
+
{
|
991
|
+
rb_raise(rb_eArgError, "Cannot find args entries table");
|
992
|
+
}
|
993
|
+
if (TYPE(tbl_val) != T_ARRAY)
|
994
|
+
{
|
995
|
+
rb_raise(rb_eArgError, "args description must be an array");
|
996
|
+
}
|
997
|
+
relocs->args_len = RARRAY_LEN(tbl_val);
|
998
|
+
relocs->args_adr = ALLOC_N(struct rb_args_info *, relocs->args_len);
|
999
|
+
for (i = 0; i < relocs->args_len; i++)
|
1000
|
+
{
|
1001
|
+
int ord;
|
1002
|
+
VALUE ainfo_val, *aiptr;
|
1003
|
+
struct rb_args_info *ainfo;
|
1004
|
+
|
1005
|
+
relocs->args_adr[i] = ALLOC(struct rb_args_info);
|
1006
|
+
ainfo_val = RARRAY_PTR(tbl_val)[i];
|
1007
|
+
aiptr = RARRAY_PTR(ainfo_val);
|
1008
|
+
ainfo = relocs->args_adr[i];
|
1009
|
+
|
1010
|
+
if (TYPE(ainfo_val) != T_ARRAY || RARRAY_LEN(ainfo_val) != 10)
|
1011
|
+
{
|
1012
|
+
rb_raise(rb_eArgError, "args entry %d is corrupted", i);
|
1013
|
+
}
|
1014
|
+
// Load unresolved values
|
1015
|
+
ainfo->pre_init = (NODE *) FIX2LONG(aiptr[0]); // Node ordinal
|
1016
|
+
ainfo->post_init = (NODE *) FIX2LONG(aiptr[1]); // Node ordinal
|
1017
|
+
ainfo->pre_args_num = FIX2INT(aiptr[2]); // No ordinal resolving
|
1018
|
+
ainfo->post_args_num = FIX2INT(aiptr[3]); // No ordinal resolving
|
1019
|
+
ainfo->first_post_arg = FIX2INT(aiptr[4]); // Symbolic ordinal
|
1020
|
+
ainfo->rest_arg = FIX2INT(aiptr[5]); // Symbolic ordinal
|
1021
|
+
ainfo->block_arg = FIX2INT(aiptr[6]); // Symbolic ordinal
|
1022
|
+
ainfo->kw_args = (NODE *) FIX2LONG(aiptr[7]); // Node ordinal
|
1023
|
+
ainfo->kw_rest_arg = (NODE *) FIX2LONG(aiptr[8]); // Node ordinal
|
1024
|
+
ainfo->opt_args = (NODE *) FIX2LONG(aiptr[9]); // Node ordinal
|
1025
|
+
// Resolve nodes
|
1026
|
+
ord = (int) (((VALUE) ainfo->pre_init) & 0xFFFFFFFF);
|
1027
|
+
if (ord < -1 || ord >= relocs->nodes_len)
|
1028
|
+
rb_raise(rb_eArgError, "Invalid node ordinal %d", ord);
|
1029
|
+
ainfo->pre_init = (ord == -1) ? NULL : relocs->nodes_adr[ord];
|
1030
|
+
|
1031
|
+
ord = (int) (((VALUE) ainfo->post_init) & 0xFFFFFFFF);
|
1032
|
+
if (ord < -1 || ord >= relocs->nodes_len)
|
1033
|
+
rb_raise(rb_eArgError, "Invalid node ordinal %d", ord);
|
1034
|
+
ainfo->post_init = (ord == -1) ? NULL : relocs->nodes_adr[ord];
|
1035
|
+
|
1036
|
+
ord = (int) (((VALUE) ainfo->kw_args) & 0xFFFFFFFF);
|
1037
|
+
if (ord < -1 || ord >= relocs->nodes_len)
|
1038
|
+
rb_raise(rb_eArgError, "Invalid node ordinal %d", ord);
|
1039
|
+
ainfo->kw_args = (ord == -1) ? NULL : relocs->nodes_adr[ord];
|
1040
|
+
|
1041
|
+
ord = (int) (((VALUE) ainfo->kw_rest_arg) & 0xFFFFFFFF);
|
1042
|
+
if (ord < -1 || ord >= relocs->nodes_len)
|
1043
|
+
rb_raise(rb_eArgError, "Invalid node ordinal %d", ord);
|
1044
|
+
ainfo->kw_rest_arg = (ord == -1) ? NULL : relocs->nodes_adr[ord];
|
1045
|
+
|
1046
|
+
ord = (int) (((VALUE) ainfo->opt_args) & 0xFFFFFFFF);
|
1047
|
+
if (ord < -1 || ord >= relocs->nodes_len)
|
1048
|
+
rb_raise(rb_eArgError, "Invalid node ordinal %d", ord);
|
1049
|
+
ainfo->opt_args = (ord == -1) ? NULL : relocs->nodes_adr[ord];
|
1050
|
+
// Resolve symbolic ordinals
|
1051
|
+
ord = ainfo->first_post_arg;
|
1052
|
+
if (ord < -1 || ord >= relocs->syms_len)
|
1053
|
+
rb_raise(rb_eArgError, "1- Invalid symbol ID ordinal %d", ord);
|
1054
|
+
ainfo->first_post_arg = (ord == -1) ? 0 : relocs->syms_adr[ord];
|
1055
|
+
|
1056
|
+
ord = ainfo->rest_arg;
|
1057
|
+
if (ord < -1 || ord >= relocs->syms_len)
|
1058
|
+
rb_raise(rb_eArgError, "2- Invalid symbol ID ordinal %d", ord);
|
1059
|
+
ainfo->rest_arg = (ord == -1) ? 0 : relocs->syms_adr[ord];
|
1060
|
+
|
1061
|
+
ord = ainfo->block_arg;
|
1062
|
+
if (ord < -1 || ord >= relocs->syms_len)
|
1063
|
+
rb_raise(rb_eArgError, "3- Invalid symbol ID ordinal %d", ord);
|
1064
|
+
ainfo->block_arg = (ord == -1) ? 0 : relocs->syms_adr[ord];
|
1065
|
+
}
|
1066
|
+
}
|
1067
|
+
#endif
|
1068
|
+
|
1069
|
+
void load_nodes_from_str(VALUE data, NODEObjAddresses *relocs)
|
1070
|
+
{
|
1071
|
+
int i, j;
|
1072
|
+
VALUE tbl_val = rb_hash_aref(data, ID2SYM(rb_intern("nodes")));
|
1073
|
+
unsigned char *bin = (unsigned char *) RSTRING_PTR(tbl_val);
|
1074
|
+
NODE *node = NULL;
|
1075
|
+
for (i = 0; i < relocs->nodes_len; i++)
|
1076
|
+
{
|
1077
|
+
int rtypes[4];
|
1078
|
+
VALUE u[3], flags;
|
1079
|
+
// Read data structure info
|
1080
|
+
for (j = 0; j < 4; j++)
|
1081
|
+
rtypes[j] = *bin++;
|
1082
|
+
flags = bin_to_value(bin, rtypes[3]); bin += rtypes[3];
|
1083
|
+
for (j = 0; j < 3; j++)
|
1084
|
+
{
|
1085
|
+
int val_len = (rtypes[j] & 0xF0) >> 4;
|
1086
|
+
u[j] = bin_to_value(bin, val_len);
|
1087
|
+
bin += val_len;
|
1088
|
+
rtypes[j] &= 0x0F;
|
1089
|
+
|
1090
|
+
}
|
1091
|
+
if ((char *)bin - RSTRING_PTR(tbl_val) > RSTRING_LEN(tbl_val))
|
1092
|
+
rb_raise(rb_eArgError, "Nodes binary dump is too short");
|
1093
|
+
// Resolving all addresses
|
1094
|
+
for (j = 0; j < 3; j++)
|
1095
|
+
{
|
1096
|
+
switch(rtypes[j])
|
1097
|
+
{
|
1098
|
+
case VL_RAW: // Do nothing: it is raw data
|
1099
|
+
break;
|
1100
|
+
case VL_NODE:
|
1101
|
+
if (u[j] >= (unsigned int) relocs->nodes_len)
|
1102
|
+
rb_raise(rb_eArgError, "Cannot resolve VL_NODE entry %d", (int) u[j]);
|
1103
|
+
u[j] = (VALUE) relocs->nodes_adr[u[j]];
|
1104
|
+
if (TYPE(u[j]) != T_NODE)
|
1105
|
+
rb_raise(rb_eArgError, "load_nodes_from_str: nodes memory corrupted");
|
1106
|
+
break;
|
1107
|
+
case VL_ID:
|
1108
|
+
if (u[j] >= (unsigned int) relocs->syms_len)
|
1109
|
+
rb_raise(rb_eArgError, "Cannot resolve VL_ID entry %d", (int) u[j]);
|
1110
|
+
u[j] = relocs->syms_adr[u[j]];
|
1111
|
+
break;
|
1112
|
+
case VL_GVAR:
|
1113
|
+
if (u[j] >= (unsigned int) relocs->gvars_len)
|
1114
|
+
rb_raise(rb_eArgError, "Cannot resolve VL_GVAR entry %d", (int) u[j]);
|
1115
|
+
u[j] = (VALUE) relocs->gvars_adr[u[j]];
|
1116
|
+
break;
|
1117
|
+
case VL_IDTABLE:
|
1118
|
+
if (u[j] >= (unsigned int) relocs->idtbls_len)
|
1119
|
+
rb_raise(rb_eArgError, "Cannot resolve VL_IDTABLE entry %d", (int) u[j]);
|
1120
|
+
u[j] = (VALUE) relocs->idtbls_adr[u[j]];
|
1121
|
+
break;
|
1122
|
+
#ifdef USE_RB_ARGS_INFO
|
1123
|
+
case VL_ARGS:
|
1124
|
+
if (u[j] >= (unsigned int) relocs->args_len)
|
1125
|
+
rb_raise(rb_eArgError, "Cannot resolve VL_ARGS entry %d", (int) u[j]);
|
1126
|
+
u[j] = (VALUE) relocs->args_adr[u[j]];
|
1127
|
+
break;
|
1128
|
+
#endif
|
1129
|
+
case VL_LIT:
|
1130
|
+
if (u[j] >= (unsigned int) relocs->lits_len)
|
1131
|
+
rb_raise(rb_eArgError, "Cannot resolve VL_LIT entry %d", (int) u[j]);
|
1132
|
+
u[j] = (VALUE) relocs->lits_adr[u[j]];
|
1133
|
+
break;
|
1134
|
+
default:
|
1135
|
+
rb_raise(rb_eArgError, "Unknown RTYPE %d", rtypes[j]);
|
1136
|
+
}
|
1137
|
+
}
|
1138
|
+
|
1139
|
+
// Fill classic node structure
|
1140
|
+
node = relocs->nodes_adr[i];
|
1141
|
+
#ifdef RESET_GC_FLAGS
|
1142
|
+
flags = flags & (~0x3); // Ruby 1.9.x -- specific thing
|
1143
|
+
#endif
|
1144
|
+
node->flags = (flags << 5) | T_NODE;
|
1145
|
+
node->nd_reserved = 0;
|
1146
|
+
node->u1.value = u[0];
|
1147
|
+
node->u2.value = u[1];
|
1148
|
+
node->u3.value = u[2];
|
1149
|
+
}
|
1150
|
+
}
|
1151
|
+
|
1152
|
+
/*
|
1153
|
+
* Returns the value of string hash field using symbolic key
|
1154
|
+
*/
|
1155
|
+
static VALUE get_hash_strfield(VALUE hash, const char *idtxt)
|
1156
|
+
{
|
1157
|
+
VALUE str = rb_hash_aref(hash, ID2SYM(rb_intern(idtxt)));
|
1158
|
+
if (TYPE(str) != T_STRING)
|
1159
|
+
{
|
1160
|
+
rb_raise(rb_eArgError, "Hash field %s is not a string", idtxt);
|
1161
|
+
return Qnil;
|
1162
|
+
}
|
1163
|
+
else
|
1164
|
+
{
|
1165
|
+
return str;
|
1166
|
+
}
|
1167
|
+
}
|
1168
|
+
|
1169
|
+
/*
|
1170
|
+
* Check validity of node hash representation signatures ("magic" values)
|
1171
|
+
*/
|
1172
|
+
static VALUE check_hash_magic(VALUE data)
|
1173
|
+
{
|
1174
|
+
VALUE val, refval;
|
1175
|
+
// MAGIC signature must be valid
|
1176
|
+
val = get_hash_strfield(data, "MAGIC");
|
1177
|
+
if (strcmp("NODEMARSHAL10", RSTRING_PTR(val)))
|
1178
|
+
rb_raise(rb_eArgError, "Bad value of MAGIC signature");
|
1179
|
+
// RUBY_PLATFORM signature must match the current platform
|
1180
|
+
val = get_hash_strfield(data, "RUBY_PLATFORM");
|
1181
|
+
refval = rb_const_get(rb_cObject, rb_intern("RUBY_PLATFORM"));
|
1182
|
+
if (strcmp(RSTRING_PTR(refval), RSTRING_PTR(val)))
|
1183
|
+
rb_raise(rb_eArgError, "Incompatible RUBY_PLATFORM value %s", RSTRING_PTR(val));
|
1184
|
+
// RUBY_VERSION signature must match the used Ruby interpreter
|
1185
|
+
val = get_hash_strfield(data, "RUBY_VERSION");
|
1186
|
+
refval = rb_const_get(rb_cObject, rb_intern("RUBY_VERSION"));
|
1187
|
+
if (strcmp(RSTRING_PTR(refval), RSTRING_PTR(val)))
|
1188
|
+
rb_raise(rb_eArgError, "Incompatible RUBY_VERSION value %s", RSTRING_PTR(val));
|
1189
|
+
return Qtrue;
|
1190
|
+
}
|
1191
|
+
|
1192
|
+
/*
|
1193
|
+
* Part 5. C-to-Ruby interface
|
1194
|
+
*
|
1195
|
+
*/
|
1196
|
+
|
1197
|
+
/*
|
1198
|
+
* Restore Ruby node from the binary blob (dump)
|
1199
|
+
*/
|
1200
|
+
static VALUE m_nodedump_from_memory(VALUE self, VALUE dump)
|
1201
|
+
{
|
1202
|
+
VALUE cMarshal, data, val, val_relocs;
|
1203
|
+
int num_of_nodes;
|
1204
|
+
NODEObjAddresses *relocs;
|
1205
|
+
/* DISABLE GARBAGE COLLECTOR (required for stable loading
|
1206
|
+
of large node trees */
|
1207
|
+
rb_gc_disable();
|
1208
|
+
/* Wrap struct for relocations */
|
1209
|
+
val_relocs = Data_Make_Struct(cNodeObjAddresses, NODEObjAddresses,
|
1210
|
+
NULL, NODEObjAddresses_free, relocs); // This data envelope cannot exist without NODE
|
1211
|
+
/* Load and unpack our dump */
|
1212
|
+
cMarshal = rb_const_get(rb_cObject, rb_intern("Marshal"));
|
1213
|
+
data = rb_funcall(cMarshal, rb_intern("load"), 1, dump);
|
1214
|
+
if (TYPE(data) != T_HASH)
|
1215
|
+
{
|
1216
|
+
rb_raise(rb_eArgError, "Input dump is corrupted");
|
1217
|
+
}
|
1218
|
+
val = rb_hash_aref(data, ID2SYM(rb_intern("num_of_nodes")));
|
1219
|
+
if (val == Qnil)
|
1220
|
+
{
|
1221
|
+
rb_raise(rb_eArgError, "num_of_nodes not found");
|
1222
|
+
}
|
1223
|
+
else
|
1224
|
+
{
|
1225
|
+
num_of_nodes = FIX2INT(val);
|
1226
|
+
}
|
1227
|
+
/* Check "magic" signature and platform identifiers */
|
1228
|
+
check_hash_magic(data);
|
1229
|
+
/* Get the information about the source file that was compiled to the node */
|
1230
|
+
// a) node name
|
1231
|
+
val = rb_hash_aref(data, ID2SYM(rb_intern("nodename")));
|
1232
|
+
if (val == Qnil || TYPE(val) == T_STRING)
|
1233
|
+
rb_iv_set(self, "@nodename", val);
|
1234
|
+
else
|
1235
|
+
rb_raise(rb_eArgError, "nodename value is corrupted");
|
1236
|
+
// b) file name
|
1237
|
+
val = rb_hash_aref(data, ID2SYM(rb_intern("filename")));
|
1238
|
+
if (val == Qnil || TYPE(val) == T_STRING)
|
1239
|
+
rb_iv_set(self, "@filename", val);
|
1240
|
+
else
|
1241
|
+
rb_raise(rb_eArgError, "filename value is corrupted");
|
1242
|
+
// c) file path
|
1243
|
+
val = rb_hash_aref(data, ID2SYM(rb_intern("filepath")));
|
1244
|
+
if (val == Qnil || TYPE(val) == T_STRING)
|
1245
|
+
rb_iv_set(self, "@filepath", val);
|
1246
|
+
else
|
1247
|
+
rb_raise(rb_eArgError, "filepath value is corrupted");
|
1248
|
+
/* Load all required data */
|
1249
|
+
resolve_syms_ords(data, relocs); // Symbols
|
1250
|
+
resolve_lits_ords(data, relocs); // Literals
|
1251
|
+
resolve_gvars_ords(data, relocs); // Global entries (with symbol ID resolving)
|
1252
|
+
resolve_idtbls_ords(data, relocs); // Identifiers tables (with symbol ID resolving)
|
1253
|
+
resolve_nodes_ords(data, num_of_nodes, relocs); // Allocate memory for all nodes
|
1254
|
+
#ifdef USE_RB_ARGS_INFO
|
1255
|
+
resolve_args_ords(data, relocs); // Load args entries with symbols ID and nodes resolving
|
1256
|
+
#endif
|
1257
|
+
load_nodes_from_str(data, relocs);
|
1258
|
+
/* Save the loaded node tree and collect garbage */
|
1259
|
+
rb_iv_set(self, "@node", (VALUE) relocs->nodes_adr[0]);
|
1260
|
+
rb_iv_set(self, "@num_of_nodes", INT2FIX(num_of_nodes));
|
1261
|
+
rb_iv_set(self, "@obj_addresses", val_relocs);
|
1262
|
+
rb_gc_enable();
|
1263
|
+
rb_gc_start();
|
1264
|
+
return self;
|
1265
|
+
}
|
1266
|
+
|
1267
|
+
|
1268
|
+
/*
|
1269
|
+
* Return array with the list of symbols
|
1270
|
+
*/
|
1271
|
+
static VALUE m_nodedump_symbols(VALUE self)
|
1272
|
+
{
|
1273
|
+
int i;
|
1274
|
+
VALUE val_relocs, val_nodeinfo, syms;
|
1275
|
+
// Variant 1: node loaded from file
|
1276
|
+
val_relocs = rb_iv_get(self, "@obj_addresses");
|
1277
|
+
if (val_relocs != Qnil)
|
1278
|
+
{
|
1279
|
+
NODEObjAddresses *relocs;
|
1280
|
+
Data_Get_Struct(val_relocs, NODEObjAddresses, relocs);
|
1281
|
+
syms = rb_ary_new();
|
1282
|
+
for (i = 0; i < relocs->syms_len; i++)
|
1283
|
+
rb_ary_push(syms, ID2SYM(relocs->syms_adr[i]));
|
1284
|
+
return syms;
|
1285
|
+
}
|
1286
|
+
// Variant 2: node saved to file (parsed from memory)
|
1287
|
+
val_nodeinfo = rb_iv_get(self, "@nodeinfo");
|
1288
|
+
if (val_nodeinfo != Qnil)
|
1289
|
+
{
|
1290
|
+
NODEInfo *ninfo;
|
1291
|
+
VALUE *ary;
|
1292
|
+
Data_Get_Struct(val_nodeinfo, NODEInfo, ninfo);
|
1293
|
+
syms = rb_funcall(ninfo->syms.vals, rb_intern("values"), 0);
|
1294
|
+
ary = RARRAY_PTR(syms);
|
1295
|
+
for (i = 0; i < RARRAY_LEN(syms); i++)
|
1296
|
+
{
|
1297
|
+
ary[i] = rb_funcall(ary[i], rb_intern("to_sym"), 0);
|
1298
|
+
}
|
1299
|
+
return syms;
|
1300
|
+
}
|
1301
|
+
rb_raise(rb_eArgError, "Symbol information not initialized. Run to_hash before reading.");
|
1302
|
+
}
|
1303
|
+
|
1304
|
+
/*
|
1305
|
+
* Return array with the list of literals
|
1306
|
+
*/
|
1307
|
+
static VALUE m_nodedump_literals(VALUE self)
|
1308
|
+
{
|
1309
|
+
int i;
|
1310
|
+
VALUE val_relocs, val_nodeinfo, lits;
|
1311
|
+
// Variant 1: node loaded from file
|
1312
|
+
val_relocs = rb_iv_get(self, "@obj_addresses");
|
1313
|
+
if (val_relocs != Qnil)
|
1314
|
+
{
|
1315
|
+
NODEObjAddresses *relocs;
|
1316
|
+
|
1317
|
+
Data_Get_Struct(val_relocs, NODEObjAddresses, relocs);
|
1318
|
+
lits = rb_ary_new();
|
1319
|
+
for (i = 0; i < relocs->lits_len; i++)
|
1320
|
+
rb_ary_push(lits, rb_funcall(relocs->lits_adr[i], rb_intern("dup"), 0));
|
1321
|
+
return lits;
|
1322
|
+
}
|
1323
|
+
// Variant 2: node saved to file (parsed from memory)
|
1324
|
+
val_nodeinfo = rb_iv_get(self, "@nodeinfo");
|
1325
|
+
if (val_nodeinfo != Qnil)
|
1326
|
+
{
|
1327
|
+
NODEInfo *ninfo;
|
1328
|
+
VALUE *ary;
|
1329
|
+
Data_Get_Struct(val_nodeinfo, NODEInfo, ninfo);
|
1330
|
+
lits = rb_funcall(ninfo->lits.vals, rb_intern("values"), 0);
|
1331
|
+
ary = RARRAY_PTR(lits);
|
1332
|
+
for (i = 0; i < RARRAY_LEN(lits); i++)
|
1333
|
+
{
|
1334
|
+
int t = TYPE(ary[i]);
|
1335
|
+
if (t != T_SYMBOL && t != T_FLOAT && t != T_FIXNUM)
|
1336
|
+
ary[i] = rb_funcall(ary[i], rb_intern("dup"), 0);
|
1337
|
+
}
|
1338
|
+
return lits;
|
1339
|
+
}
|
1340
|
+
rb_raise(rb_eArgError, "Literals information not initialized. Run to_hash before reading.");
|
1341
|
+
}
|
1342
|
+
|
1343
|
+
|
1344
|
+
|
1345
|
+
/*
|
1346
|
+
* call-seq:
|
1347
|
+
* obj.compile
|
1348
|
+
*
|
1349
|
+
* Creates the RubyVM::InstructionSequence object from the node
|
1350
|
+
*/
|
1351
|
+
static VALUE m_nodedump_compile(VALUE self)
|
1352
|
+
{
|
1353
|
+
NODE *node = RNODE(rb_iv_get(self, "@node"));
|
1354
|
+
VALUE nodename = rb_iv_get(self, "@nodename");
|
1355
|
+
VALUE filename = rb_iv_get(self, "@filename");
|
1356
|
+
VALUE filepath = rb_iv_get(self, "@filepath");
|
1357
|
+
return rb_iseq_new_top(node, nodename, filename, filepath, Qfalse);
|
1358
|
+
}
|
1359
|
+
|
1360
|
+
/*
|
1361
|
+
* Parses Ruby file with the source code and saves the node
|
1362
|
+
*/
|
1363
|
+
static VALUE m_nodedump_from_source(VALUE self, VALUE file)
|
1364
|
+
{
|
1365
|
+
VALUE line = INT2FIX(1), f, node, filepath;
|
1366
|
+
const char *fname;
|
1367
|
+
|
1368
|
+
rb_secure(1);
|
1369
|
+
FilePathValue(file);
|
1370
|
+
fname = StringValueCStr(file);
|
1371
|
+
/* Remember information about the file */
|
1372
|
+
rb_iv_set(self, "@nodename", rb_str_new2("<main>"));
|
1373
|
+
rb_iv_set(self, "@filename", file);
|
1374
|
+
filepath = rb_funcall(rb_cFile, rb_intern("realpath"), 1, file); // Envelope for rb_realpath_internal
|
1375
|
+
rb_iv_set(self, "@filepath", filepath);
|
1376
|
+
/* Create node from the source */
|
1377
|
+
f = rb_file_open_str(file, "r");
|
1378
|
+
node = (VALUE) rb_compile_file(fname, f, NUM2INT(line));
|
1379
|
+
rb_iv_set(self, "@node", node);
|
1380
|
+
return self;
|
1381
|
+
}
|
1382
|
+
|
1383
|
+
/*
|
1384
|
+
* Parses Ruby string with the source code and saves the node
|
1385
|
+
*/
|
1386
|
+
static VALUE m_nodedump_from_string(VALUE self, VALUE str)
|
1387
|
+
{
|
1388
|
+
VALUE line = INT2FIX(1), node;
|
1389
|
+
const char *fname = "STRING";
|
1390
|
+
Check_Type(str, T_STRING);
|
1391
|
+
rb_secure(1);
|
1392
|
+
/* Create empty information about the file */
|
1393
|
+
rb_iv_set(self, "@nodename", rb_str_new2("<main>"));
|
1394
|
+
if (RUBY_API_VERSION_MAJOR == 1)
|
1395
|
+
{ /* For Ruby 1.9.x */
|
1396
|
+
rb_iv_set(self, "@filename", Qnil);
|
1397
|
+
rb_iv_set(self, "@filepath", Qnil);
|
1398
|
+
}
|
1399
|
+
else
|
1400
|
+
{ /* For Ruby 2.x */
|
1401
|
+
rb_iv_set(self, "@filename", rb_str_new2("<compiled>"));
|
1402
|
+
rb_iv_set(self, "@filepath", rb_str_new2("<compiled>"));
|
1403
|
+
}
|
1404
|
+
/* Create node from the string */
|
1405
|
+
rb_gc_disable();
|
1406
|
+
node = (VALUE) rb_compile_string(fname, str, NUM2INT(line));
|
1407
|
+
rb_iv_set(self, "@node", node);
|
1408
|
+
rb_gc_enable();
|
1409
|
+
rb_gc_start();
|
1410
|
+
return self;
|
1411
|
+
}
|
1412
|
+
|
1413
|
+
/*
|
1414
|
+
* call-seq:
|
1415
|
+
* obj.new(:srcfile, filename) # Will load source file from the disk
|
1416
|
+
* obj.new(:binfile, filename) # Will load file with node binary dump from the disk
|
1417
|
+
* obj.new(:srcmemory, srcstr) # Will load source code from the string
|
1418
|
+
* obj.new(:binmemory, binstr) # Will load node binary dump from the string
|
1419
|
+
*
|
1420
|
+
* Creates NodeMarshal class example from the source code or dumped
|
1421
|
+
* syntax tree (NODEs), i.e. preparsed and packed source code. Created
|
1422
|
+
* object can be used either for code execution or for saving it
|
1423
|
+
* in the preparsed form (useful for code obfuscation/protection)
|
1424
|
+
*/
|
1425
|
+
static VALUE m_nodedump_init(VALUE self, VALUE source, VALUE info)
|
1426
|
+
{
|
1427
|
+
ID id_usr;
|
1428
|
+
Check_Type(source, T_SYMBOL);
|
1429
|
+
id_usr = SYM2ID(source);
|
1430
|
+
if (id_usr == rb_intern("srcfile"))
|
1431
|
+
{
|
1432
|
+
return m_nodedump_from_source(self, info);
|
1433
|
+
}
|
1434
|
+
else if (id_usr == rb_intern("srcmemory"))
|
1435
|
+
{
|
1436
|
+
return m_nodedump_from_string(self, info);
|
1437
|
+
}
|
1438
|
+
else if (id_usr == rb_intern("binmemory"))
|
1439
|
+
{
|
1440
|
+
return m_nodedump_from_memory(self, info);
|
1441
|
+
}
|
1442
|
+
else if (id_usr == rb_intern("binfile"))
|
1443
|
+
{
|
1444
|
+
VALUE cFile = rb_const_get(rb_cObject, rb_intern("File"));
|
1445
|
+
VALUE bin = rb_funcall(cFile, rb_intern("binread"), 1, info);
|
1446
|
+
return m_nodedump_from_memory(self, bin);
|
1447
|
+
}
|
1448
|
+
else
|
1449
|
+
{
|
1450
|
+
rb_raise(rb_eArgError, "Invalid source type (it must be :srcfile, :srcmemory, :binmemory of :binfile)");
|
1451
|
+
}
|
1452
|
+
return Qnil;
|
1453
|
+
}
|
1454
|
+
|
1455
|
+
/*
|
1456
|
+
* call-seq:
|
1457
|
+
* obj.dump_tree
|
1458
|
+
*
|
1459
|
+
* Transforms Ruby syntax tree (NODE) to the text string using
|
1460
|
+
* rb_parser_dump_tree function from node.c (see Ruby source code).
|
1461
|
+
*/
|
1462
|
+
static VALUE m_nodedump_parser_dump_tree(VALUE self)
|
1463
|
+
{
|
1464
|
+
NODE *node = RNODE(rb_iv_get(self, "@node"));
|
1465
|
+
return rb_parser_dump_tree(node, 0);
|
1466
|
+
}
|
1467
|
+
|
1468
|
+
/*
|
1469
|
+
* Prints the node tree in the short variant
|
1470
|
+
*/
|
1471
|
+
static VALUE m_nodedump_dump_tree_short(VALUE self)
|
1472
|
+
{
|
1473
|
+
VALUE str = rb_str_new2(""); // Output string
|
1474
|
+
NODE *node = RNODE(rb_iv_get(self, "@node"));
|
1475
|
+
print_node(str, node, 0);
|
1476
|
+
return str;
|
1477
|
+
}
|
1478
|
+
|
1479
|
+
/*
|
1480
|
+
* call-seq:
|
1481
|
+
* obj.to_hash
|
1482
|
+
*
|
1483
|
+
* Converts NodeMarshal class example to the hash that contains full
|
1484
|
+
* and independent from data structures memory addresses information.
|
1485
|
+
* Format of the obtained hash depends on used platform (especially
|
1486
|
+
* size of the pointer) and Ruby version.
|
1487
|
+
*
|
1488
|
+
* <b>Format of the hash</b>
|
1489
|
+
*
|
1490
|
+
* <i>Part 1: Signatures</i>
|
1491
|
+
*
|
1492
|
+
* - <tt>MAGIC</tt> -- NODEMARSHAL10
|
1493
|
+
* - <tt>RUBY_PLATFORM</tt> -- saved <tt>RUBY_PLATFORM</tt> constant value
|
1494
|
+
* - <tt>RUBY_VERSION</tt> -- saved <tt>RUBY_VERSION</tt> constant value
|
1495
|
+
*
|
1496
|
+
* <i>Part 2: Program loadable elements.</i>
|
1497
|
+
*
|
1498
|
+
* All loadable elements are arrays. Index of the array element means
|
1499
|
+
* its identifier that is used in the node tree.
|
1500
|
+
*
|
1501
|
+
* - <tt>literals</tt> -- program literals (strings, ranges etc.)
|
1502
|
+
* - <tt>symbols</tt> -- program symbols
|
1503
|
+
* - <tt>global_entries</tt> -- global variables information
|
1504
|
+
* - <tt>id_tables</tt> -- array of arrays. Each array contains symbols IDs
|
1505
|
+
* - <tt>args</tt> -- information about code block argument(s)
|
1506
|
+
*
|
1507
|
+
* <i>Part 3: Nodes information</i>
|
1508
|
+
* - <tt>nodes</tt> -- string that contains binary encoded information
|
1509
|
+
* about the nodes
|
1510
|
+
*/
|
1511
|
+
static VALUE m_nodedump_to_hash(VALUE self)
|
1512
|
+
{
|
1513
|
+
NODE *node = RNODE(rb_iv_get(self, "@node"));
|
1514
|
+
NODEInfo *info;
|
1515
|
+
VALUE ans, num, val_info;
|
1516
|
+
// DISABLE GARBAGE COLLECTOR (important for dumping)
|
1517
|
+
rb_gc_disable();
|
1518
|
+
// Allocate memory for the information about node
|
1519
|
+
val_info = Data_Make_Struct(cNodeInfo, NODEInfo,
|
1520
|
+
NODEInfo_mark, NODEInfo_free, info); // This data envelope cannot exist without NODE
|
1521
|
+
NODEInfo_init(info);
|
1522
|
+
rb_iv_set(self, "@nodeinfo", val_info);
|
1523
|
+
// Convert node to NODEInfo structure
|
1524
|
+
num = INT2FIX(count_num_of_nodes(node, node, info));
|
1525
|
+
ans = NODEInfo_toHash(info);
|
1526
|
+
rb_hash_aset(ans, ID2SYM(rb_intern("num_of_nodes")), num);
|
1527
|
+
rb_hash_aset(ans, ID2SYM(rb_intern("nodename")), rb_iv_get(self, "@nodename"));
|
1528
|
+
rb_hash_aset(ans, ID2SYM(rb_intern("filename")), rb_iv_get(self, "@filename"));
|
1529
|
+
rb_hash_aset(ans, ID2SYM(rb_intern("filepath")), rb_iv_get(self, "@filepath"));
|
1530
|
+
// ENABLE GARBAGE COLLECTOR (important for dumping)
|
1531
|
+
rb_gc_enable();
|
1532
|
+
return ans;
|
1533
|
+
}
|
1534
|
+
|
1535
|
+
/*
|
1536
|
+
* call-seq:
|
1537
|
+
* obj.to_bin
|
1538
|
+
*
|
1539
|
+
* Converts NodeMarshal class example to the binary string that
|
1540
|
+
* can be saved to the file and used for loading the node from the file.
|
1541
|
+
* Format of the obtained binary dump depends on used platform (especially
|
1542
|
+
* size of the pointer) and Ruby version.
|
1543
|
+
*/
|
1544
|
+
static VALUE m_nodedump_to_bin(VALUE self)
|
1545
|
+
{
|
1546
|
+
VALUE hash = m_nodedump_to_hash(self);
|
1547
|
+
VALUE cMarshal = rb_const_get(rb_cObject, rb_intern("Marshal"));
|
1548
|
+
return rb_funcall(cMarshal, rb_intern("dump"), 1, hash);
|
1549
|
+
}
|
1550
|
+
|
1551
|
+
/*
|
1552
|
+
* Gives the information about the node
|
1553
|
+
*/
|
1554
|
+
static VALUE m_nodedump_inspect(VALUE self)
|
1555
|
+
{
|
1556
|
+
static char str[1024], buf[512];
|
1557
|
+
VALUE num_of_nodes, nodename, filepath, filename;
|
1558
|
+
VALUE val_obj_addresses, val_nodeinfo;
|
1559
|
+
// Get generic information about node
|
1560
|
+
num_of_nodes = rb_iv_get(self, "@num_of_nodes");
|
1561
|
+
nodename = rb_iv_get(self, "@nodename");
|
1562
|
+
filepath = rb_iv_get(self, "@filepath");
|
1563
|
+
filename = rb_iv_get(self, "@filename");
|
1564
|
+
// Generate string with generic information about node
|
1565
|
+
sprintf(str,
|
1566
|
+
"----- NodeMarshal:0x%"PRIxPTR"\n"
|
1567
|
+
" num_of_nodes: %d\n nodename: %s\n filepath: %s\n filename: %s\n",
|
1568
|
+
self,
|
1569
|
+
(num_of_nodes == Qnil) ? -1 : FIX2INT(num_of_nodes),
|
1570
|
+
(nodename == Qnil) ? "nil" : RSTRING_PTR(nodename),
|
1571
|
+
(filepath == Qnil) ? "nil" : RSTRING_PTR(filepath),
|
1572
|
+
(filename == Qnil) ? "nil" : RSTRING_PTR(filename)
|
1573
|
+
);
|
1574
|
+
// Check if the information about node struct is available
|
1575
|
+
val_nodeinfo = rb_iv_get(self, "@nodeinfo");
|
1576
|
+
val_obj_addresses = rb_iv_get(self, "@obj_addresses");
|
1577
|
+
if (val_nodeinfo == Qnil && val_obj_addresses == Qnil)
|
1578
|
+
{
|
1579
|
+
m_nodedump_to_hash(self);
|
1580
|
+
val_nodeinfo = rb_iv_get(self, "@nodeinfo");
|
1581
|
+
}
|
1582
|
+
// Information about preparsed node
|
1583
|
+
// a) NODEInfo struct
|
1584
|
+
if (val_nodeinfo == Qnil)
|
1585
|
+
{
|
1586
|
+
sprintf(buf, " NODEInfo struct is empty\n");
|
1587
|
+
}
|
1588
|
+
else
|
1589
|
+
{
|
1590
|
+
NODEInfo *ninfo;
|
1591
|
+
Data_Get_Struct(val_nodeinfo, NODEInfo, ninfo);
|
1592
|
+
sprintf(buf,
|
1593
|
+
" NODEInfo struct:\n"
|
1594
|
+
" syms hash len (Symbols): %d\n"
|
1595
|
+
" lits hash len (Literals): %d\n"
|
1596
|
+
" idtabs hash len (ID tables): %d\n"
|
1597
|
+
" gentries hash len (Global vars): %d\n"
|
1598
|
+
" nodes hash len (Nodes): %d\n"
|
1599
|
+
#ifdef USE_RB_ARGS_INFO
|
1600
|
+
" args hash len (args info): %d\n"
|
1601
|
+
#endif
|
1602
|
+
,
|
1603
|
+
FIX2INT(rb_funcall(ninfo->syms.vals, rb_intern("length"), 0)),
|
1604
|
+
FIX2INT(rb_funcall(ninfo->lits.vals, rb_intern("length"), 0)),
|
1605
|
+
FIX2INT(rb_funcall(ninfo->idtabs.vals, rb_intern("length"), 0)),
|
1606
|
+
FIX2INT(rb_funcall(ninfo->gentries.vals, rb_intern("length"), 0)),
|
1607
|
+
FIX2INT(rb_funcall(ninfo->nodes.vals, rb_intern("length"), 0))
|
1608
|
+
#ifdef USE_RB_ARGS_INFO
|
1609
|
+
,
|
1610
|
+
FIX2INT(rb_funcall(ninfo->args.vals, rb_intern("length"), 0))
|
1611
|
+
#endif
|
1612
|
+
);
|
1613
|
+
}
|
1614
|
+
strcat(str, buf);
|
1615
|
+
// b) NODEObjAddresses struct
|
1616
|
+
if (val_obj_addresses == Qnil)
|
1617
|
+
{
|
1618
|
+
sprintf(buf, " NODEObjAddresses struct is empty\n");
|
1619
|
+
}
|
1620
|
+
else
|
1621
|
+
{
|
1622
|
+
NODEObjAddresses *objadr;
|
1623
|
+
Data_Get_Struct(val_obj_addresses, NODEObjAddresses, objadr);
|
1624
|
+
sprintf(buf,
|
1625
|
+
" NODEObjAddresses struct:\n"
|
1626
|
+
" syms_len (Num of symbols): %d\n"
|
1627
|
+
" lits_len (Num of literals): %d\n"
|
1628
|
+
" idtbls_len (Num of ID tables): %d\n"
|
1629
|
+
" gvars_len (Num of global vars): %d\n"
|
1630
|
+
" nodes_len (Num of nodes): %d\n"
|
1631
|
+
#ifdef USE_RB_ARGS_INFO
|
1632
|
+
" args_len: (Num of args info): %d\n"
|
1633
|
+
#endif
|
1634
|
+
, objadr->syms_len, objadr->lits_len,
|
1635
|
+
objadr->idtbls_len, objadr->gvars_len,
|
1636
|
+
objadr->nodes_len
|
1637
|
+
#ifdef USE_RB_ARGS_INFO
|
1638
|
+
, objadr->args_len
|
1639
|
+
#endif
|
1640
|
+
);
|
1641
|
+
}
|
1642
|
+
strcat(str, buf);
|
1643
|
+
strcat(str, "------------------\n");
|
1644
|
+
// Generate output string
|
1645
|
+
return rb_str_new2(str);
|
1646
|
+
}
|
1647
|
+
|
1648
|
+
/*
|
1649
|
+
* Returns node name (usually <main>)
|
1650
|
+
*/
|
1651
|
+
static VALUE m_nodedump_nodename(VALUE self)
|
1652
|
+
{
|
1653
|
+
return rb_funcall(rb_iv_get(self, "@nodename"), rb_intern("dup"), 0);
|
1654
|
+
}
|
1655
|
+
|
1656
|
+
/*
|
1657
|
+
* Returns name of file that was used for node generation and will be used
|
1658
|
+
* by YARV (or nil/<compiled> if a string of code was used)
|
1659
|
+
*/
|
1660
|
+
static VALUE m_nodedump_filename(VALUE self)
|
1661
|
+
{
|
1662
|
+
return rb_funcall(rb_iv_get(self, "@filename"), rb_intern("dup"), 0);
|
1663
|
+
}
|
1664
|
+
|
1665
|
+
/*
|
1666
|
+
* Sets name of file that was used for node generation and will be used
|
1667
|
+
* by YARV (or nil/<compiled> if a string of code was used)
|
1668
|
+
*/
|
1669
|
+
static VALUE m_nodedump_set_filename(VALUE self, VALUE val)
|
1670
|
+
{
|
1671
|
+
if (val != Qnil)
|
1672
|
+
{
|
1673
|
+
Check_Type(val, T_STRING);
|
1674
|
+
rb_iv_set(self, "@filename", rb_funcall(val, rb_intern("dup"), 0));
|
1675
|
+
}
|
1676
|
+
else
|
1677
|
+
{
|
1678
|
+
rb_iv_set(self, "@filename", Qnil);
|
1679
|
+
}
|
1680
|
+
return self;
|
1681
|
+
}
|
1682
|
+
|
1683
|
+
/*
|
1684
|
+
* Returns path of file that was used for node generation and will be used
|
1685
|
+
* by YARV (or nil/<compiled> if a string of code was used)
|
1686
|
+
*/
|
1687
|
+
static VALUE m_nodedump_filepath(VALUE self)
|
1688
|
+
{
|
1689
|
+
return rb_funcall(rb_iv_get(self, "@filepath"), rb_intern("dup"), 0);
|
1690
|
+
}
|
1691
|
+
|
1692
|
+
/*
|
1693
|
+
* call-seq:
|
1694
|
+
* obj.filepath=value
|
1695
|
+
*
|
1696
|
+
* Sets the path of file that was used for node generation and will
|
1697
|
+
* be used by YARV (or nil/<compiled> if a string of code was used)
|
1698
|
+
*/
|
1699
|
+
static VALUE m_nodedump_set_filepath(VALUE self, VALUE val)
|
1700
|
+
{
|
1701
|
+
if (val != Qnil)
|
1702
|
+
{
|
1703
|
+
Check_Type(val, T_STRING);
|
1704
|
+
rb_iv_set(self, "@filepath", rb_funcall(val, rb_intern("dup"), 0));
|
1705
|
+
}
|
1706
|
+
else
|
1707
|
+
{
|
1708
|
+
rb_iv_set(self, "@filepath", Qnil);
|
1709
|
+
}
|
1710
|
+
return self;
|
1711
|
+
}
|
1712
|
+
|
1713
|
+
/*
|
1714
|
+
* call-seq:
|
1715
|
+
* NodeMarshal.base85r_encode(input) -> output
|
1716
|
+
*
|
1717
|
+
* Encode arbitrary binary string to the ASCII string
|
1718
|
+
* using modified version of BASE85 (useful for obfuscation
|
1719
|
+
* of .rb source files)
|
1720
|
+
*/
|
1721
|
+
static VALUE m_base85r_encode(VALUE obj, VALUE input)
|
1722
|
+
{
|
1723
|
+
return base85r_encode(input);
|
1724
|
+
}
|
1725
|
+
|
1726
|
+
/*
|
1727
|
+
* call-seq:
|
1728
|
+
* NodeMarshal.base85r_decode(input) -> output
|
1729
|
+
*
|
1730
|
+
* Decode ASCII string in the modified BASE85 format
|
1731
|
+
* to the binary string (useful for obfuscation of .rb
|
1732
|
+
* source files)
|
1733
|
+
*/
|
1734
|
+
static VALUE m_base85r_decode(VALUE obj, VALUE input)
|
1735
|
+
{
|
1736
|
+
return base85r_decode(input);
|
1737
|
+
}
|
1738
|
+
|
1739
|
+
/* call-seq:
|
1740
|
+
* obj.to_bin
|
1741
|
+
*
|
1742
|
+
* Converts NodeMarshal class example to the text string (modified Base85 encoding) that
|
1743
|
+
* can be saved to the file and used for loading the node from the file.
|
1744
|
+
* Format of the obtained binary dump depends on used platform (especially
|
1745
|
+
* size of the pointer) and Ruby version.
|
1746
|
+
*/
|
1747
|
+
static VALUE m_nodedump_to_text(VALUE self)
|
1748
|
+
{
|
1749
|
+
VALUE bin = m_nodedump_to_bin(self);
|
1750
|
+
return base85r_encode(bin);
|
1751
|
+
}
|
1752
|
+
|
1753
|
+
/*
|
1754
|
+
* Returns node object
|
1755
|
+
*/
|
1756
|
+
static VALUE m_nodedump_node(VALUE self)
|
1757
|
+
{
|
1758
|
+
return rb_iv_get(self, "@node");
|
1759
|
+
}
|
1760
|
+
|
1761
|
+
|
1762
|
+
/*
|
1763
|
+
* This class can load and save Ruby code in the form of the
|
1764
|
+
* platform-dependent syntax tree (made of NODEs). Such function
|
1765
|
+
* allows to hide the source code from users. Main features:
|
1766
|
+
*
|
1767
|
+
* - Irreversible transformation of Ruby source code to the syntax tree
|
1768
|
+
* - Representation of syntax tree in binary form dependent from the platform and Ruby version
|
1769
|
+
* - Simple options for node inspection
|
1770
|
+
* - Ruby 1.9.3 and 2.2.1 support
|
1771
|
+
*/
|
1772
|
+
void Init_nodemarshal()
|
1773
|
+
{
|
1774
|
+
static VALUE cNodeMarshal;
|
1775
|
+
init_nodes_table(nodes_ctbl, NODES_CTBL_SIZE);
|
1776
|
+
base85r_init_tables();
|
1777
|
+
|
1778
|
+
cNodeMarshal = rb_define_class("NodeMarshal", rb_cObject);
|
1779
|
+
rb_define_singleton_method(cNodeMarshal, "base85r_encode", RUBY_METHOD_FUNC(m_base85r_encode), 1);
|
1780
|
+
rb_define_singleton_method(cNodeMarshal, "base85r_decode", RUBY_METHOD_FUNC(m_base85r_decode), 1);
|
1781
|
+
|
1782
|
+
rb_define_method(cNodeMarshal, "initialize", RUBY_METHOD_FUNC(m_nodedump_init), 2);
|
1783
|
+
rb_define_method(cNodeMarshal, "to_hash", RUBY_METHOD_FUNC(m_nodedump_to_hash), 0);
|
1784
|
+
rb_define_method(cNodeMarshal, "to_bin", RUBY_METHOD_FUNC(m_nodedump_to_bin), 0);
|
1785
|
+
rb_define_method(cNodeMarshal, "to_text", RUBY_METHOD_FUNC(m_nodedump_to_text), 0);
|
1786
|
+
rb_define_method(cNodeMarshal, "dump_tree", RUBY_METHOD_FUNC(m_nodedump_parser_dump_tree), 0);
|
1787
|
+
rb_define_method(cNodeMarshal, "dump_tree_short", RUBY_METHOD_FUNC(m_nodedump_dump_tree_short), 0);
|
1788
|
+
rb_define_method(cNodeMarshal, "compile", RUBY_METHOD_FUNC(m_nodedump_compile), 0);
|
1789
|
+
// Methods for working with the information about the node
|
1790
|
+
// a) literals, symbols, generic information
|
1791
|
+
rb_define_method(cNodeMarshal, "symbols", RUBY_METHOD_FUNC(m_nodedump_symbols), 0);
|
1792
|
+
rb_define_method(cNodeMarshal, "literals", RUBY_METHOD_FUNC(m_nodedump_literals), 0);
|
1793
|
+
rb_define_method(cNodeMarshal, "inspect", RUBY_METHOD_FUNC(m_nodedump_inspect), 0);
|
1794
|
+
rb_define_method(cNodeMarshal, "node", RUBY_METHOD_FUNC(m_nodedump_node), 0);
|
1795
|
+
// b) node and file names
|
1796
|
+
rb_define_method(cNodeMarshal, "nodename", RUBY_METHOD_FUNC(m_nodedump_nodename), 0);
|
1797
|
+
rb_define_method(cNodeMarshal, "filename", RUBY_METHOD_FUNC(m_nodedump_filename), 0);
|
1798
|
+
rb_define_method(cNodeMarshal, "filename=", RUBY_METHOD_FUNC(m_nodedump_set_filename), 1);
|
1799
|
+
rb_define_method(cNodeMarshal, "filepath", RUBY_METHOD_FUNC(m_nodedump_filepath), 0);
|
1800
|
+
rb_define_method(cNodeMarshal, "filepath=", RUBY_METHOD_FUNC(m_nodedump_set_filepath), 1);
|
1801
|
+
// C structure wrappers
|
1802
|
+
cNodeObjAddresses = rb_define_class("NodeObjAddresses", rb_cObject);
|
1803
|
+
cNodeInfo = rb_define_class("NodeInfo", rb_cObject);
|
1804
|
+
}
|