3 #include "shotgun/lib/shotgun.h"
4 #include "shotgun/lib/cpu.h"
5 #include "shotgun/lib/machine.h"
6 #include "shotgun/lib/tuple.h"
7 #include "shotgun/lib/methctx.h"
8 #include "shotgun/lib/object.h"
9 #include "shotgun/lib/bytearray.h"
10 #include "shotgun/lib/string.h"
11 #include "shotgun/lib/module.h"
12 #include "shotgun/lib/class.h"
13 #include "shotgun/lib/hash.h"
14 #include "shotgun/lib/lookuptable.h"
15 #include "shotgun/lib/symbol.h"
18 cpu c
= (cpu
)calloc(1, sizeof(struct rubinius_cpu
));
19 c
->paths
= ptr_array_new(8);
23 void cpu_destroy(cpu c
) {
24 /* BUG. Doesn't free the operand stacks. */
25 ptr_array_free(c
->paths
);
29 void cpu_initialize(STATE
, cpu c
) {
30 state
->global
->tuple
= Qnil
;
31 state
->global
->hash
= Qnil
;
32 state
->global
->methtbl
= Qnil
;
33 c
->stack_top
= (OBJECT
*)calloc(InitialStackSize
, SIZE_OF_OBJECT
);
34 c
->sp_ptr
= c
->stack_top
;
35 c
->stack_size
= InitialStackSize
;
40 c
->enclosing_class
= Qnil
;
44 c
->current_task
= Qnil
;
45 c
->debug_channel
= Qnil
;
46 c
->control_channel
= Qnil
;
48 cpu_sampler_init(state
, c
);
51 void cpu_setup_top_scope(STATE
, cpu c
) {
52 c
->enclosing_class
= state
->global
->object
;
55 OBJECT
cpu_scope_push(STATE
, cpu c
, OBJECT mod
) {
56 OBJECT scope
= staticscope_allocate(state
);
57 staticscope_set_module(scope
, mod
);
58 staticscope_set_parent(scope
, c
->current_scope
);
60 c
->current_scope
= scope
;
64 OBJECT
cpu_scope_pop(STATE
, cpu c
) {
65 c
->current_scope
= staticscope_get_parent(c
->current_scope
);
66 return c
->current_scope
;
69 /* initializes VM core: from global methods, main routine to current scope, thread and so forth */
70 void cpu_initialize_context(STATE
, cpu c
) {
71 c
->active_context
= Qnil
;
73 c
->home_context
= c
->active_context
;
74 c
->enclosing_class
= state
->global
->object
;
76 c
->main
= object_new(state
);
77 rbs_const_set(state
, state
->global
->object
, "MAIN", c
->main
);
79 state
->global
->method_missing
= string_to_sym(state
,
80 string_new(state
, "method_missing"));
82 state
->global
->sym_inherited
= string_to_sym(state
,
83 string_new(state
, "inherited"));
85 state
->global
->sym_method_added
= string_to_sym(state
,
86 string_new(state
, "__method_added__"));
88 state
->global
->sym_s_method_added
= string_to_sym(state
,
89 string_new(state
, "singleton_method_added"));
91 state
->global
->sym_plus
= symbol_from_cstr(state
, "+");
92 state
->global
->sym_minus
= symbol_from_cstr(state
, "-");
93 state
->global
->sym_equal
= symbol_from_cstr(state
, "==");
94 state
->global
->sym_nequal
= symbol_from_cstr(state
, "!=");
95 state
->global
->sym_tequal
= symbol_from_cstr(state
, "===");
96 state
->global
->sym_lt
= symbol_from_cstr(state
, "<");
97 state
->global
->sym_gt
= symbol_from_cstr(state
, ">");
98 state
->global
->sym_send
= symbol_from_cstr(state
, "__send__");
99 state
->global
->sym_public
= symbol_from_cstr(state
, "public");
100 state
->global
->sym_private
= symbol_from_cstr(state
, "private");
101 state
->global
->sym_protected
= symbol_from_cstr(state
, "protected");
102 state
->global
->sym_const_missing
= SYM("const_missing");
103 state
->global
->sym_object_id
= SYM("object_id");
104 state
->global
->sym_from_literal
= SYM("from_literal");
105 state
->global
->sym_opened_class
= SYM("opened_class");
106 state
->global
->sym_initialize
= SYM("initialize");
107 state
->global
->sym_init_copy
= SYM("initialize_copy");
108 state
->global
->sym_call
= SYM("call");
110 c
->current_thread
= Qnil
;
111 c
->current_scope
= staticscope_allocate(state
);
112 staticscope_set_module(c
->current_scope
, BASIC_CLASS(object
));
114 c
->current_thread
= cpu_thread_new(state
, c
);
115 c
->main_thread
= c
->current_thread
;
116 c
->current_task
= cpu_thread_get_task(state
, c
->current_thread
);
117 c
->main_task
= c
->current_task
;
119 cpu_scope_push(state
, c
, BASIC_CLASS(object
));
120 state
->global
->top_scope
= c
->current_scope
;
123 void cpu_add_roots(STATE
, cpu c
, ptr_array roots
) {
126 #define ar(obj) if(REFERENCE_P(obj)) { \
127 ptr_array_append(roots, (xpointer)obj); \
130 ar(c
->active_context
);
136 ar(c
->enclosing_class
);
138 ar(c
->current_thread
);
142 ar(c
->debug_channel
);
143 ar(c
->control_channel
);
144 ar(c
->current_scope
);
146 len
= ptr_array_length(c
->paths
);
147 ptr_array_append(roots
, (xpointer
)I2N(len
));
148 // printf("Paths: %d\n", len);
149 for(i
= 0; i
< len
; i
++) {
150 t
= ptr_array_remove_index_ordered(c
->paths
, 0);
151 //printf("Pulled %s out of paths.\n", _inspect(t));
154 //printf("Paths should be empty: %d\n", c->paths->len);
159 int cpu_ip2line(STATE
, OBJECT meth
, int ip
) {
161 int l
, total
, start
, nd
, op
;
163 if(meth
->obj_type
!= CMethodType
) return 0;
165 lines
= cmethod_get_lines(meth
);
166 total
= NUM_FIELDS(lines
);
167 for(l
= 0; l
< total
; l
++) {
168 tup
= tuple_at(state
, lines
, l
);
169 start
= N2I(tuple_at(state
, tup
, 0));
170 nd
= N2I(tuple_at(state
, tup
, 1));
171 op
= N2I(tuple_at(state
, tup
, 2));
173 if(ip
>= start
&& ip
<= nd
) {
181 void cpu_update_roots(STATE
, cpu c
, ptr_array roots
, int start
) {
184 #define ar(obj) if(REFERENCE_P(obj)) { \
185 tmp = ptr_array_get_index(roots, start++); \
189 ar(c
->active_context
);
195 ar(c
->enclosing_class
);
197 ar(c
->current_thread
);
201 ar(c
->debug_channel
);
202 ar(c
->control_channel
);
203 ar(c
->current_scope
);
205 tmp
= ptr_array_get_index(roots
, start
++);
206 len
= N2I((OBJECT
)tmp
);
207 for(i
= 0; i
< len
; start
++, i
++) {
208 tmp
= ptr_array_get_index(roots
, start
);
209 //printf("Adding path %s back in...\n", _inspect(tmp));
210 ptr_array_append(c
->paths
, tmp
);
212 //printf("Paths is %d\n", c->paths->len);
218 OBJECT
cpu_new_exception(STATE
, cpu c
, OBJECT klass
, const char *msg
) {
221 obj
= class_new_instance(state
, klass
);
222 str
= string_new(state
, msg
);
223 exception_set_message(obj
, str
);
224 methctx_reference(state
, c
->active_context
);
225 exception_set_context(obj
, c
->active_context
);
229 OBJECT
cpu_new_exception2(STATE
, cpu c
, OBJECT klass
, const char *msg
, ...) {
231 static char buffer
[1024];
236 count
= vsnprintf(buffer
, 1024, msg
, ap
);
239 obj
= class_new_instance(state
, klass
);
240 str
= string_new2(state
, buffer
, count
);
241 exception_set_message(obj
, str
);
242 methctx_reference(state
, c
->active_context
);
243 exception_set_context(obj
, c
->active_context
);
248 OBJECT
cpu_const_get_in_context(STATE
, cpu c
, OBJECT sym
) {
249 OBJECT cur
, klass
, start
, tbl
, val
;
252 /* Look up the lexical scope first */
254 cref
= cpu_current_scope(state
, c
);
256 start
= state
->global
->object
;
260 while(!NIL_P(cbase
)) {
261 klass
= staticscope_get_module(cbase
);
263 /* If we hit Object in the chain, we stop there. */
264 if(klass
== state
->global
->object
) break;
266 tbl
= module_get_constants(klass
);
267 val
= lookuptable_find(state
, tbl
, sym
);
268 if(val
!= Qundef
) return val
;
270 cbase
= staticscope_get_parent(cbase
);
273 start
= cur
= staticscope_get_module(cref
);
277 tbl
= module_get_constants(cur
);
278 val
= lookuptable_find(state
, tbl
, sym
);
279 if(val
!= Qundef
) return val
;
280 cur
= module_get_superclass(cur
);
284 // As a last rescue, we search in Object's constants
285 tbl
= module_get_constants(state
->global
->object
);
286 val
= lookuptable_find(state
, tbl
, sym
);
287 if(val
!= Qundef
) return val
;
290 cpu_send(state
, c
, start
, state
->global
->sym_const_missing
, 1, Qnil
);
294 OBJECT
cpu_const_get_from(STATE
, cpu c
, OBJECT sym
, OBJECT under
) {
295 OBJECT cur
, tbl
, val
;
298 // printf("Looking for %s under %s.\n", rbs_symbol_to_cstring(state, sym), rbs_symbol_to_cstring(state, module_get_name(under)));
300 if(!(RISA(under
, class) || RISA(under
, module
))) {
302 snprintf(str
, 256, "%s is not a class/module", _inspect(under
));
303 cpu_raise_exception(state
, c
,
304 cpu_new_exception(state
, c
, state
->global
->exc_type
, str
));
312 // printf(" looking in %s\n", rbs_symbol_to_cstring(state, module_get_name(cur)));
314 tbl
= module_get_constants(cur
);
315 val
= lookuptable_find(state
, tbl
, sym
);
319 /* Object's superclass MUST be nil, but we check directly just
321 if(cur
== state
->global
->object
) break;
322 cur
= class_get_superclass(cur
);
325 // Didn't find it, so fire const_missing
327 cpu_send(state
, c
, under
, state
->global
->sym_const_missing
, 1, Qnil
);
331 OBJECT
cpu_const_get(STATE
, cpu c
, OBJECT sym
, OBJECT under
) {
332 return cpu_const_get_from(state
, c
, sym
, under
);
335 OBJECT
cpu_const_set(STATE
, cpu c
, OBJECT sym
, OBJECT val
, OBJECT under
) {
338 tbl
= module_get_constants(under
);
339 lookuptable_store(state
, tbl
, sym
, val
);
343 void cpu_set_encloser_path(STATE
, cpu c
, OBJECT cls
) {
346 len
= ptr_array_length(c
->paths
);
347 ptr_array_append(c
->paths
, (xpointer
)c
->enclosing_class
);
348 method
= cpu_current_method(state
, c
);
350 cmethod_set_staticscope(method
, cpu_scope_push(state
, c
, cls
));
351 c
->enclosing_class
= cls
;
354 void cpu_push_encloser(STATE
, cpu c
) {
356 len
= ptr_array_length(c
->paths
);
358 c
->enclosing_class
= (OBJECT
)ptr_array_remove_index_ordered(c
->paths
, len
- 1);
359 cpu_scope_pop(state
, c
);
363 /* Increments serial numbers up the superclass chain. */
364 static void cpu_increment_serials(STATE
, OBJECT module
, OBJECT sym
) {
367 while(!NIL_P(module
)) {
368 tbl
= module_get_method_table(module
);
369 meth
= lookuptable_fetch(state
, tbl
, sym
);
371 if(REFERENCE_P(meth
)) {
372 if(CLASS_OBJECT(meth
) == BASIC_CLASS(tuple
)) {
373 meth
= tuple_at(state
, meth
, 1);
375 fast_inc(meth
, CMETHOD_f_SERIAL
);
378 module
= class_get_superclass(module
);
382 void cpu_add_method(STATE
, cpu c
, OBJECT target
, OBJECT sym
, OBJECT method
) {
383 OBJECT meths
, vis
, cref
;
385 if(!ISA(target
, BASIC_CLASS(module
))) {
386 cref
= cmethod_get_staticscope(cpu_current_method(state
, c
));
388 target
= state
->global
->object
;
390 target
= staticscope_get_module(cref
);
394 cpu_clear_cache_for_method(state
, c
, sym
, FALSE
);
396 cpu_increment_serials(state
, target
, sym
);
397 meths
= module_get_method_table(target
);
399 switch(c
->call_flags
) {
402 vis
= state
->global
->sym_public
;
405 vis
= state
->global
->sym_private
;
408 vis
= state
->global
->sym_protected
;
412 /* force initialize to be private. */
413 if(sym
== state
->global
->sym_initialize
) {
414 vis
= state
->global
->sym_private
;
417 if(EXCESSIVE_TRACING
) {
418 printf("=> Adding method %s to %s.\n", rbs_symbol_to_cstring(state
, sym
), _inspect(target
));
421 // HACK. the 10 sucks, it protects things that go in a method table, but
422 // aren't exactly CompiledMethods.
423 // A method inherits the static scope of the method that that add/attaches it.
424 if(NUM_FIELDS(method
) > 10 && NIL_P(cmethod_get_staticscope(method
))) {
425 cmethod_set_staticscope(method
, cpu_current_scope(state
, c
));
428 lookuptable_store(state
, meths
, sym
, tuple_new2(state
, 2, vis
, method
));
432 void cpu_attach_method(STATE
, cpu c
, OBJECT target
, OBJECT sym
, OBJECT method
) {
434 meta
= object_metaclass(state
, target
);
435 /* static visibility scope doesn't impact singleton classes.
436 we force it to public everytime it's used. */
438 cpu_add_method(state
, c
, meta
, sym
, method
);
441 /* Updates the cpu registers by reading out of the active context.
442 These get out of sync when the GC runs. */
443 void cpu_hard_cache(STATE
, cpu c
) {
444 struct fast_context
*fc
;
448 fc
= (struct fast_context
*)BYTES_OF(c
->active_context
);