Fix yet another bug in GC, in which the instruction pointer was not
[panda.git] / src / st-processor.c
blob8548f8e76f60818aa83e5810796cd3093d9589ed
2 #include "st-types.h"
3 #include "st-compiler.h"
4 #include "st-universe.h"
5 #include "st-dictionary.h"
6 #include "st-symbol.h"
7 #include "st-object.h"
8 #include "st-behavior.h"
9 #include "st-context.h"
10 #include "st-primitives.h"
11 #include "st-method.h"
12 #include "st-array.h"
13 #include "st-association.h"
15 #include <stdlib.h>
16 #include <setjmp.h>
18 static st_oop
19 method_context_new (st_processor *pr)
21 st_oop context;
22 int stack_size;
23 st_oop *stack;
24 bool large;
26 large = st_method_get_large_context (pr->new_method);
27 stack_size = large ? 32 : 12;
29 context = st_memory_allocate_context (large);
31 ST_CONTEXT_PART_SENDER (context) = pr->context;
32 ST_CONTEXT_PART_IP (context) = st_smi_new (0);
33 ST_CONTEXT_PART_SP (context) = st_smi_new (0);
34 ST_METHOD_CONTEXT_RECEIVER (context) = pr->message_receiver;
35 ST_METHOD_CONTEXT_METHOD (context) = pr->new_method;
37 stack = ST_METHOD_CONTEXT (context)->stack;
38 for (st_uint i=0; i < stack_size; i++)
39 stack[i] = st_nil;
41 return context;
44 static st_oop
45 block_context_new (st_processor *pr, st_uint initial_ip, st_uint argcount)
47 st_oop home;
48 st_oop context;
49 st_oop method;
50 st_oop *stack;
51 st_uint stack_size;
53 stack_size = 32;
55 context = st_memory_allocate (ST_SIZE_OOPS (struct st_block_context) + stack_size);
56 st_object_initialize_header (context, st_block_context_class);
57 st_object_set_large_context (context, true);
59 if (ST_OBJECT_CLASS (pr->context) == st_block_context_class)
60 home = ST_BLOCK_CONTEXT_HOME (pr->context);
61 else
62 home = pr->context;
64 ST_CONTEXT_PART_SENDER (context) = st_nil;
65 ST_CONTEXT_PART_IP (context) = st_smi_new (0);
66 ST_CONTEXT_PART_SP (context) = st_smi_new (0);
68 ST_BLOCK_CONTEXT_INITIALIP (context) = st_smi_new (initial_ip);
69 ST_BLOCK_CONTEXT_ARGCOUNT (context) = st_smi_new (argcount);
70 ST_BLOCK_CONTEXT_CALLER (context) = st_nil;
71 ST_BLOCK_CONTEXT_HOME (context) = home;
73 stack = ST_BLOCK_CONTEXT (context)->stack;
74 for (st_uint i=0; i < stack_size; i++)
75 stack[i] = st_nil;
77 return context;
80 static void
81 create_actual_message (st_processor *pr)
83 st_oop *elements;
84 st_oop array;
86 array = st_object_new_arrayed (st_array_class, pr->message_argcount);
87 elements = st_array_elements (array);
88 for (st_uint i = 0; i < pr->message_argcount; i++)
89 elements[i] = pr->stack[pr_sp - pr->message_argcount + i];
91 pr_sp -= pr->message_argcount;
93 ST_STACK_PUSH (pr, st_message_new (pr->message_selector, array));
95 pr->message_selector = st_selector_doesNotUnderstand;
96 pr->message_argcount = 1;
99 static inline st_oop
100 lookup_method (st_processor *pr, st_oop class)
102 st_oop method;
103 st_oop parent = class;
104 st_uint index;
106 index = ST_METHOD_CACHE_HASH (class, pr->message_selector);
108 if (pr->method_cache[index].class == class &&
109 pr->method_cache[index].selector == pr->message_selector)
110 return pr->method_cache[index].method;
112 while (parent != st_nil) {
113 method = st_dictionary_at (ST_BEHAVIOR_METHOD_DICTIONARY (parent), pr->message_selector);
114 if (method != st_nil) {
115 index = ST_METHOD_CACHE_HASH (parent, pr->message_selector);
116 pr->method_cache[index].class = class;
117 pr->method_cache[index].selector = pr->message_selector;
118 pr->method_cache[index].method = method;
119 return method;
121 parent = ST_BEHAVIOR_SUPERCLASS (parent);
124 if (pr->message_selector == st_selector_doesNotUnderstand) {
125 fprintf (stderr, "no method found for #doesNotUnderstand:");
126 exit(1);
129 create_actual_message (pr);
131 return lookup_method (pr, class);
134 st_oop
135 st_processor_lookup_method (st_processor *pr, st_oop class)
137 return lookup_method (pr, class);
141 * Creates a new method context. Parameterised by
142 * @sender, @receiver, @method, and @argcount
144 * Message arguments are copied into the new context's temporary
145 * frame. Receiver and arguments are then popped off the stack.
148 static inline void
149 activate_method (st_processor *pr)
151 st_oop context;
152 st_oop *arguments;
154 context = method_context_new (pr);
156 arguments = ST_METHOD_CONTEXT_TEMPORARY_FRAME (context);
157 for (st_uint i = 0; i < pr->message_argcount; i++)
158 arguments[i] = pr->stack[pr_sp - pr->message_argcount + i];
160 pr_sp -= pr->message_argcount + 1;
162 st_processor_set_active_context (pr, context);
165 void
166 st_processor_execute_method (st_processor *pr)
168 st_uint primitive_index;
169 st_method_flags flags;
171 flags = st_method_get_flags (pr->new_method);
172 if (flags == ST_METHOD_PRIMITIVE) {
173 primitive_index = st_method_get_primitive_index (pr->new_method);
174 pr->success = true;
175 st_primitives[primitive_index].func (pr);
176 if (ST_LIKELY (pr->success))
177 return;
180 activate_method (pr);
184 void
185 st_processor_set_active_context (st_processor *pr,
186 st_oop context)
188 st_oop home;
190 /* save executation state of active context */
191 if (pr->context != st_nil) {
192 ST_CONTEXT_PART_IP (pr->context) = st_smi_new (pr_ip - st_method_bytecode_bytes (pr->method));
193 ST_CONTEXT_PART_SP (pr->context) = st_smi_new (pr_sp);
196 if (st_object_class (context) == st_block_context_class) {
198 home = ST_BLOCK_CONTEXT_HOME (context);
200 pr->method = ST_METHOD_CONTEXT_METHOD (home);
201 pr->receiver = ST_METHOD_CONTEXT_RECEIVER (home);
202 pr->literals = st_array_elements (ST_METHOD_LITERALS (pr->method));
203 pr->temps = ST_METHOD_CONTEXT_TEMPORARY_FRAME (home);
204 pr->stack = ST_BLOCK_CONTEXT_STACK (context);
205 } else {
206 pr->method = ST_METHOD_CONTEXT_METHOD (context);
207 pr->receiver = ST_METHOD_CONTEXT_RECEIVER (context);
208 pr->literals = st_array_elements (ST_METHOD_LITERALS (pr->method));
209 pr->temps = ST_METHOD_CONTEXT_TEMPORARY_FRAME (context);
210 pr->stack = ST_METHOD_CONTEXT_STACK (context);
213 pr->context = context;
214 pr_sp = st_smi_value (ST_CONTEXT_PART_SP (context));
215 pr_ip = st_method_bytecode_bytes (pr->method) + st_smi_value (ST_CONTEXT_PART_IP (context));
216 pr->bytecode = st_method_bytecode_bytes (pr->method);
220 void
221 st_processor_prologue (st_processor *pr)
223 if (st_verbose_mode ()) {
224 fprintf (stderr, "** gc: totalPauseTime: %.6fs\n", st_timespec_to_double_seconds (&memory->total_pause_time));
228 void
229 st_processor_send_selector (st_processor *pr,
230 st_oop selector,
231 st_uint argcount)
233 st_oop method;
234 st_uint primitive_index;
235 st_method_flags flags;
237 pr->message_argcount = argcount;
238 pr->message_receiver = pr->stack[pr_sp - argcount - 1];
239 pr->message_selector = selector;
241 pr->new_method = st_processor_lookup_method (pr, st_object_class (pr->message_receiver));
243 flags = st_method_get_flags (pr->new_method);
244 if (flags == ST_METHOD_PRIMITIVE) {
245 primitive_index = st_method_get_primitive_index (pr->new_method);
246 pr->success = true;
247 st_primitives[primitive_index].func (pr);
248 if (ST_LIKELY (pr->success))
249 return;
252 activate_method (pr);
255 #define SEND_SELECTOR(pr, selector, argcount) \
256 st_processor_send_selector (pr, selector, argcount); \
258 #define ACTIVATE_CONTEXT(pr, context) \
259 st_processor_set_active_context (pr, context); \
261 #define ACTIVATE_METHOD(pr) \
262 activate_method (pr); \
264 #define EXECUTE_PRIMITIVE(pr, index) \
265 pr->success = true; \
266 st_primitives[index].func (pr);
268 #define SEND_TEMPLATE(pr) \
269 st_uint prim; \
270 st_method_flags flags; \
272 pr_ip += 1; \
274 pr->new_method = st_processor_lookup_method (pr, st_object_class (pr->message_receiver));\
276 flags = st_method_get_flags (pr->new_method); \
277 if (flags == ST_METHOD_PRIMITIVE) { \
278 prim = st_method_get_primitive_index (pr->new_method); \
280 EXECUTE_PRIMITIVE (pr, prim); \
281 if (ST_LIKELY (pr->success)) \
282 NEXT (); \
285 ACTIVATE_METHOD (pr);
288 #ifdef __GNUC__
289 #define I_HAS_COMPUTED_GOTO
290 #endif
292 #ifdef I_HAS_COMPUTED_GOTO
293 #define SWITCH(ip) \
294 static const st_pointer labels[] = \
296 NULL, \
297 && PUSH_TEMP, && PUSH_INSTVAR, \
298 && PUSH_LITERAL_CONST, && PUSH_LITERAL_VAR, \
300 && STORE_LITERAL_VAR, && STORE_TEMP, && STORE_INSTVAR, \
301 && STORE_POP_LITERAL_VAR, && STORE_POP_TEMP, && STORE_POP_INSTVAR, \
303 && PUSH_SELF, && PUSH_NIL, && PUSH_TRUE, && PUSH_FALSE, && PUSH_INTEGER, \
305 && RETURN_STACK_TOP, && BLOCK_RETURN, \
306 && POP_STACK_TOP, && DUPLICATE_STACK_TOP, \
308 && PUSH_ACTIVE_CONTEXT, && BLOCK_COPY, \
310 && JUMP_TRUE, && JUMP_FALSE, && JUMP, \
312 && SEND, && SEND_SUPER, \
314 && SEND_PLUS, && SEND_MINUS, \
315 && SEND_LT, && SEND_GT, \
316 && SEND_LE, && SEND_GE, \
317 && SEND_EQ, && SEND_NE, \
318 && SEND_MUL, && SEND_DIV, \
319 && SEND_MOD, && SEND_BITSHIFT, \
320 && SEND_BITAND, && SEND_BITOR, \
321 && SEND_BITXOR, \
323 && SEND_AT, && SEND_AT_PUT, \
324 && SEND_SIZE, && SEND_VALUE, \
325 && SEND_VALUE_ARG, && SEND_IDENTITY_EQ, \
326 && SEND_CLASS, && SEND_NEW, \
327 && SEND_NEW_ARG, \
328 }; \
329 goto *labels[*ip];
330 #else
331 #define SWITCH(ip) \
332 start: \
333 switch (*ip)
334 #endif
336 #ifdef I_HAS_COMPUTED_GOTO
337 #define CASE(OP) OP:
338 #else
339 #define CASE(OP) case OP:
340 #endif
342 #ifdef I_HAS_COMPUTED_GOTO
343 #define NEXT() goto *labels[*pr_ip]
344 #else
345 #define NEXT() goto start
346 #endif
348 const st_uchar *pr_ip;
349 st_uint pr_sp;
351 void
352 st_processor_main (st_processor *pr)
354 if (setjmp (pr->main_loop))
355 goto out;
357 pr_ip = pr->bytecode;
359 SWITCH (pr_ip) {
361 CASE (PUSH_TEMP) {
363 ST_STACK_PUSH (pr, pr->temps[pr_ip[1]]);
365 pr_ip += 2;
366 NEXT ();
369 CASE (PUSH_INSTVAR) {
371 ST_STACK_PUSH (pr, ST_OBJECT_FIELDS (pr->receiver)[pr_ip[1]]);
373 pr_ip += 2;
374 NEXT ();
377 CASE (STORE_POP_INSTVAR) {
379 ST_OBJECT_FIELDS (pr->receiver)[pr_ip[1]] = ST_STACK_POP (pr);
381 pr_ip += 2;
382 NEXT ();
385 CASE (STORE_INSTVAR) {
387 ST_OBJECT_FIELDS (pr->receiver)[pr_ip[1]] = ST_STACK_PEEK (pr);
389 pr_ip += 2;
390 NEXT ();
393 CASE (STORE_POP_TEMP) {
395 pr->temps[pr_ip[1]] = ST_STACK_POP (pr);
397 pr_ip += 2;
398 NEXT ();
401 CASE (STORE_TEMP) {
403 pr->temps[pr_ip[1]] = ST_STACK_PEEK (pr);
405 pr_ip += 2;
406 NEXT ();
409 CASE (STORE_LITERAL_VAR) {
411 ST_ASSOCIATION_VALUE (pr->literals[pr_ip[1]]) = ST_STACK_PEEK (pr);
413 pr_ip += 2;
414 NEXT ();
417 CASE (STORE_POP_LITERAL_VAR) {
419 ST_ASSOCIATION_VALUE (pr->literals[pr_ip[1]]) = ST_STACK_POP (pr);
421 pr_ip += 2;
422 NEXT ();
425 CASE (PUSH_SELF) {
427 ST_STACK_PUSH (pr, pr->receiver);
429 pr_ip += 1;
430 NEXT ();
433 CASE (PUSH_TRUE) {
435 ST_STACK_PUSH (pr, st_true);
437 pr_ip += 1;
438 NEXT ();
441 CASE (PUSH_FALSE) {
443 ST_STACK_PUSH (pr, st_false);
445 pr_ip += 1;
446 NEXT ();
449 CASE (PUSH_NIL) {
451 ST_STACK_PUSH (pr, st_nil);
453 pr_ip += 1;
454 NEXT ();
457 CASE (PUSH_INTEGER) {
459 ST_STACK_PUSH (pr, st_smi_new ((signed char) pr_ip[1]));
461 pr_ip += 2;
462 NEXT ();
465 CASE (PUSH_ACTIVE_CONTEXT) {
467 ST_STACK_PUSH (pr, pr->context);
469 pr_ip += 1;
470 NEXT ();
473 CASE (PUSH_LITERAL_CONST) {
475 ST_STACK_PUSH (pr, pr->literals[pr_ip[1]]);
477 pr_ip += 2;
478 NEXT ();
481 CASE (PUSH_LITERAL_VAR) {
483 st_oop var;
485 var = ST_ASSOCIATION (pr->literals[pr_ip[1]])->value;
487 ST_STACK_PUSH (pr, var);
489 pr_ip += 2;
490 NEXT ();
493 CASE (JUMP_TRUE) {
495 if (ST_STACK_PEEK (pr) == st_true) {
496 (void) ST_STACK_POP (pr);
497 pr_ip += 3 + *((short *) (pr_ip + 1));
498 } else if (ST_LIKELY (ST_STACK_PEEK (pr) == st_false)) {
499 (void) ST_STACK_POP (pr);
500 pr_ip += 3;
501 } else {
502 pr_ip += 3;
503 SEND_SELECTOR (pr, st_selector_mustBeBoolean, 0);
506 NEXT ();
509 CASE (JUMP_FALSE) {
511 if (ST_STACK_PEEK (pr) == st_false) {
512 (void) ST_STACK_POP (pr);
513 pr_ip += 3 + *((short *) (pr_ip + 1));
514 } else if (ST_LIKELY (ST_STACK_PEEK (pr) == st_true)) {
515 (void) ST_STACK_POP (pr);
516 pr_ip += 3;
517 } else {
518 pr_ip += 3;
519 SEND_SELECTOR (pr, st_selector_mustBeBoolean, 0);
522 NEXT ();
525 CASE (JUMP) {
527 short offset = *((short *) (pr_ip + 1));
529 pr_ip += ((offset >= 0) ? 3 : 0) + offset;
531 NEXT ();
534 CASE (SEND_PLUS) {
536 st_oop a, b;
538 if (ST_LIKELY (st_object_is_smi (pr->stack[pr_sp - 1]) &&
539 st_object_is_smi (pr->stack[pr_sp - 2]))) {
540 b = ST_STACK_POP (pr);
541 a = ST_STACK_POP (pr);
542 ST_STACK_PUSH (pr, st_smi_new (st_smi_value (a) + st_smi_value (b)));
543 pr_ip++;
544 NEXT ();
547 pr->message_argcount = 1;
548 pr->message_selector = st_specials[ST_SPECIAL_PLUS];
549 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
551 SEND_TEMPLATE (pr);
553 NEXT ();
556 CASE (SEND_MINUS) {
558 st_oop a, b;
560 if (ST_LIKELY (st_object_is_smi (pr->stack[pr_sp - 1]) &&
561 st_object_is_smi (pr->stack[pr_sp - 2]))) {
562 b = ST_STACK_POP (pr);
563 a = ST_STACK_POP (pr);
564 ST_STACK_PUSH (pr, st_smi_new (st_smi_value (a) - st_smi_value (b)));
565 pr_ip++;
566 NEXT ();
569 pr->message_argcount = 1;
570 pr->message_selector = st_specials[ST_SPECIAL_MINUS];
571 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
573 SEND_TEMPLATE (pr);
575 NEXT ();
578 CASE (SEND_MUL) {
580 st_oop a, b;
582 if (ST_LIKELY (st_object_is_smi (pr->stack[pr_sp - 1]) &&
583 st_object_is_smi (pr->stack[pr_sp - 2]))) {
584 b = ST_STACK_POP (pr);
585 a = ST_STACK_POP (pr);
586 ST_STACK_PUSH (pr, st_smi_new (st_smi_value (a) * st_smi_value (b)));
587 pr_ip++;
588 NEXT ();
591 pr->message_argcount = 1;
592 pr->message_selector = st_specials[ST_SPECIAL_MUL];
593 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
595 SEND_TEMPLATE (pr);
597 NEXT ();
601 CASE (SEND_MOD) {
603 st_oop a, b;
605 if (ST_LIKELY (st_object_is_smi (pr->stack[pr_sp - 1]) &&
606 st_object_is_smi (pr->stack[pr_sp - 2]))) {
607 b = ST_STACK_POP (pr);
608 a = ST_STACK_POP (pr);
609 ST_STACK_PUSH (pr, st_smi_new (st_smi_value (a) % st_smi_value (b)));
610 pr_ip++;
611 NEXT ();
614 pr->message_argcount = 1;
615 pr->message_selector = st_specials[ST_SPECIAL_MOD];
616 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
618 SEND_TEMPLATE (pr);
620 NEXT ();
624 CASE (SEND_DIV) {
626 pr->message_argcount = 1;
627 pr->message_selector = st_specials[ST_SPECIAL_DIV];
628 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
630 SEND_TEMPLATE (pr);
632 NEXT ();
635 CASE (SEND_BITSHIFT) {
637 st_oop a, b;
639 if (ST_LIKELY (st_object_is_smi (pr->stack[pr_sp - 1]) &&
640 st_object_is_smi (pr->stack[pr_sp - 2]))) {
641 b = ST_STACK_POP (pr);
642 a = ST_STACK_POP (pr);
643 if (st_smi_value (b) < 0) {
644 ST_STACK_PUSH (pr, st_smi_new (st_smi_value (a) >> -st_smi_value (b)));
645 } else
646 ST_STACK_PUSH (pr, st_smi_new (st_smi_value (a) << st_smi_value (b)));
647 pr_ip++;
648 NEXT ();
651 pr->message_argcount = 1;
652 pr->message_selector = st_specials[ST_SPECIAL_BITSHIFT];
653 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
655 SEND_TEMPLATE (pr);
657 NEXT ();
660 CASE (SEND_BITAND) {
662 st_oop a, b;
664 if (ST_LIKELY (st_object_is_smi (pr->stack[pr_sp - 1]) &&
665 st_object_is_smi (pr->stack[pr_sp - 2]))) {
666 b = ST_STACK_POP (pr);
667 a = ST_STACK_POP (pr);
668 ST_STACK_PUSH (pr, st_smi_new (st_smi_value (a) & st_smi_value (b)));
669 pr_ip++;
670 NEXT ();
673 pr->message_argcount = 1;
674 pr->message_selector = st_specials[ST_SPECIAL_BITAND];
675 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
677 SEND_TEMPLATE (pr);
679 NEXT ();
682 CASE (SEND_BITOR) {
684 st_oop a, b;
686 if (ST_LIKELY (st_object_is_smi (pr->stack[pr_sp - 1]) &&
687 st_object_is_smi (pr->stack[pr_sp - 2]))) {
688 b = ST_STACK_POP (pr);
689 a = ST_STACK_POP (pr);
690 ST_STACK_PUSH (pr, st_smi_new (st_smi_value (a) | st_smi_value (b)));
691 pr_ip++;
692 NEXT ();
695 pr->message_argcount = 1;
696 pr->message_selector = st_specials[ST_SPECIAL_BITOR];
697 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
699 SEND_TEMPLATE (pr);
701 NEXT ();
704 CASE (SEND_BITXOR) {
706 st_oop a, b;
708 if (ST_LIKELY (st_object_is_smi (pr->stack[pr_sp - 1]) &&
709 st_object_is_smi (pr->stack[pr_sp - 2]))) {
710 b = ST_STACK_POP (pr);
711 a = ST_STACK_POP (pr);
712 ST_STACK_PUSH (pr, st_smi_new (st_smi_value (a) ^ st_smi_value (b)));
713 pr_ip++;
714 NEXT ();
717 pr->message_argcount = 1;
718 pr->message_selector = st_specials[ST_SPECIAL_BITXOR];
719 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
721 SEND_TEMPLATE (pr);
723 NEXT ();
726 CASE (SEND_LT) {
728 st_oop a, b;
730 if (ST_LIKELY (st_object_is_smi (pr->stack[pr_sp - 1]) &&
731 st_object_is_smi (pr->stack[pr_sp - 2]))) {
732 b = ST_STACK_POP (pr);
733 a = ST_STACK_POP (pr);
734 ST_STACK_PUSH (pr, st_smi_value (a) < st_smi_value (b) ? st_true : st_false);
735 pr_ip++;
736 NEXT ();
739 pr->message_argcount = 1;
740 pr->message_selector = st_specials[ST_SPECIAL_LT];
741 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
743 SEND_TEMPLATE (pr);
745 NEXT ();
748 CASE (SEND_GT) {
750 st_oop a, b;
752 if (ST_LIKELY (st_object_is_smi (pr->stack[pr_sp - 1]) &&
753 st_object_is_smi (pr->stack[pr_sp - 2]))) {
754 b = ST_STACK_POP (pr);
755 a = ST_STACK_POP (pr);
756 ST_STACK_PUSH (pr, st_smi_value (a) > st_smi_value (b) ? st_true : st_false);
757 pr_ip++;
758 NEXT ();
761 pr->message_argcount = 1;
762 pr->message_selector = st_specials[ST_SPECIAL_GT];
763 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
765 SEND_TEMPLATE (pr);
767 NEXT ();
770 CASE (SEND_LE) {
772 st_oop a, b;
774 if (ST_LIKELY (st_object_is_smi (pr->stack[pr_sp - 1]) &&
775 st_object_is_smi (pr->stack[pr_sp - 2]))) {
776 b = ST_STACK_POP (pr);
777 a = ST_STACK_POP (pr);
778 ST_STACK_PUSH (pr, st_smi_value (a) <= st_smi_value (b) ? st_true : st_false);
779 pr_ip++;
780 NEXT ();
783 pr->message_argcount = 1;
784 pr->message_selector = st_specials[ST_SPECIAL_LE];
785 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
787 SEND_TEMPLATE (pr);
789 NEXT ();
792 CASE (SEND_GE) {
794 st_oop a, b;
796 if (ST_LIKELY (st_object_is_smi (pr->stack[pr_sp - 1]) &&
797 st_object_is_smi (pr->stack[pr_sp - 2]))) {
798 b = ST_STACK_POP (pr);
799 a = ST_STACK_POP (pr);
800 ST_STACK_PUSH (pr, st_smi_value (a) >= st_smi_value (b) ? st_true : st_false);
801 pr_ip++;
802 NEXT ();
805 pr->message_argcount = 1;
806 pr->message_selector = st_specials[ST_SPECIAL_GE];
807 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
809 SEND_TEMPLATE (pr);
811 NEXT ();
814 CASE (SEND_CLASS) {
816 pr->message_argcount = 0;
817 pr->message_selector = st_specials[ST_SPECIAL_CLASS];
818 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
820 SEND_TEMPLATE (pr);
822 NEXT ();
825 CASE (SEND_SIZE) {
827 pr->message_argcount = 0;
828 pr->message_selector = st_specials[ST_SPECIAL_SIZE];
829 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
831 SEND_TEMPLATE (pr);
833 NEXT ();
836 CASE (SEND_AT) {
838 pr->message_argcount = 1;
839 pr->message_selector = st_specials[ST_SPECIAL_AT];
840 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
842 SEND_TEMPLATE (pr);
844 NEXT ();
847 CASE (SEND_AT_PUT) {
849 pr->message_argcount = 2;
850 pr->message_selector = st_specials[ST_SPECIAL_ATPUT];
851 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
853 SEND_TEMPLATE (pr);
855 NEXT ();
858 CASE (SEND_EQ) {
860 pr->message_argcount = 1;
861 pr->message_selector = st_specials[ST_SPECIAL_EQ];
862 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
864 SEND_TEMPLATE (pr);
866 NEXT ();
869 CASE (SEND_NE) {
871 pr->message_argcount = 1;
872 pr->message_selector = st_specials[ST_SPECIAL_NE];
873 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
875 SEND_TEMPLATE (pr);
877 NEXT ();
880 CASE (SEND_IDENTITY_EQ) {
882 st_oop a, b;
883 a = ST_STACK_POP (pr);
884 b = ST_STACK_POP (pr);
886 ST_STACK_PUSH (pr, (a == b) ? st_true : st_false);
888 pr_ip += 1;
889 NEXT ();
892 CASE (SEND_VALUE) {
894 pr->message_argcount = 0;
895 pr->message_selector = st_specials[ST_SPECIAL_VALUE];
896 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
898 SEND_TEMPLATE (pr);
900 NEXT ();
903 CASE (SEND_VALUE_ARG) {
905 pr->message_argcount = 1;
906 pr->message_selector = st_specials[ST_SPECIAL_VALUE_ARG];
907 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
909 SEND_TEMPLATE (pr);
911 NEXT ();
914 CASE (SEND_NEW) {
916 pr->message_argcount = 0;
917 pr->message_selector = st_specials[ST_SPECIAL_NEW];
918 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
920 SEND_TEMPLATE (pr);
922 NEXT ();
925 CASE (SEND_NEW_ARG) {
927 pr->message_argcount = 1;
928 pr->message_selector = st_specials[ST_SPECIAL_NEW_ARG];
929 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
931 SEND_TEMPLATE (pr);
933 NEXT ();
936 CASE (SEND) {
938 st_uint primitive_index;
939 st_method_flags flags;
941 pr->message_argcount = pr_ip[1];
942 pr->message_selector = pr->literals[pr_ip[2]];
943 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
945 pr_ip += 3;
947 pr->new_method = st_processor_lookup_method (pr, st_object_class (pr->message_receiver));
949 flags = st_method_get_flags (pr->new_method);
950 if (flags == ST_METHOD_PRIMITIVE) {
951 primitive_index = st_method_get_primitive_index (pr->new_method);
953 EXECUTE_PRIMITIVE (pr, primitive_index);
954 if (ST_LIKELY (pr->success))
955 NEXT ();
958 ACTIVATE_METHOD (pr);
959 NEXT ();
962 CASE (SEND_SUPER) {
964 st_oop literal_index;
965 st_uint primitive_index;
966 st_method_flags flags;
968 pr->message_argcount = pr_ip[1];
969 pr->message_selector = pr->literals[pr_ip[2]];
970 pr->message_receiver = pr->stack[pr_sp - pr->message_argcount - 1];
972 pr_ip += 3;
974 literal_index = st_smi_value (st_arrayed_object_size (ST_METHOD_LITERALS (pr->method))) - 1;
976 pr->new_method = st_processor_lookup_method (pr, ST_BEHAVIOR_SUPERCLASS (pr->literals[literal_index]));
978 flags = st_method_get_flags (pr->new_method);
979 if (flags == ST_METHOD_PRIMITIVE) {
980 primitive_index = st_method_get_primitive_index (pr->new_method);
982 EXECUTE_PRIMITIVE (pr, primitive_index);
983 if (ST_LIKELY (pr->success))
984 NEXT ();
987 ACTIVATE_METHOD (pr);
988 NEXT ();
991 CASE (POP_STACK_TOP) {
993 (void) ST_STACK_POP (pr);
995 pr_ip += 1;
996 NEXT ();
999 CASE (DUPLICATE_STACK_TOP) {
1001 ST_STACK_PUSH (pr, ST_STACK_PEEK (pr));
1003 pr_ip += 1;
1004 NEXT ();
1007 CASE (BLOCK_COPY) {
1009 st_oop block;
1010 st_oop home;
1011 st_uint argcount = pr_ip[1];
1012 st_uint initial_ip;
1014 pr_ip += 2;
1016 initial_ip = pr_ip - pr->bytecode + 3;
1018 block = block_context_new (pr, initial_ip, argcount);
1020 ST_STACK_PUSH (pr, block);
1022 NEXT ();
1025 CASE (RETURN_STACK_TOP) {
1027 st_oop sender;
1028 st_oop value;
1030 value = ST_STACK_PEEK (pr);
1032 if (ST_OBJECT_CLASS (pr->context) == st_block_context_class)
1033 sender = ST_CONTEXT_PART_SENDER (ST_BLOCK_CONTEXT_HOME (pr->context));
1034 else
1035 sender = ST_CONTEXT_PART_SENDER (pr->context);
1037 st_assert (st_object_is_heap (sender));
1039 if (sender == st_nil) {
1040 ST_STACK_PUSH (pr, pr->context);
1041 ST_STACK_PUSH (pr, value);
1042 SEND_SELECTOR (pr, st_selector_cannotReturn, 1);
1043 NEXT ();
1046 if (ST_OBJECT_CLASS (pr->context) == st_method_context_class)
1047 st_memory_recycle_context (pr->context);
1049 ACTIVATE_CONTEXT (pr, sender);
1050 ST_STACK_PUSH (pr, value);
1052 NEXT ();
1055 CASE (BLOCK_RETURN) {
1057 st_oop caller;
1058 st_oop value;
1060 caller = ST_BLOCK_CONTEXT_CALLER (pr->context);
1061 value = ST_STACK_PEEK (pr);
1062 ACTIVATE_CONTEXT (pr, caller);
1064 /* push returned value onto caller's stack */
1065 ST_STACK_PUSH (pr, value);
1066 st_assert (pr->context == caller);
1068 NEXT ();
1072 out:
1073 st_processor_prologue (pr);
1076 void
1077 st_processor_clear_caches (st_processor *pr)
1079 for (st_uint i = 0; i < ST_METHOD_CACHE_SIZE; i++) {
1080 pr->method_cache[i].class = st_nil;
1081 pr->method_cache[i].selector = st_nil;
1082 pr->method_cache[i].method = st_nil;
1086 void
1087 st_processor_initialize (st_processor *pr)
1089 st_oop context;
1090 st_oop method;
1092 /* clear contents */
1093 memset (pr, 0, sizeof (st_processor));
1094 pr->context = st_nil;
1095 pr->receiver = st_nil;
1096 pr->method = st_nil;
1098 pr_sp = 0;
1099 pr->stack = NULL;
1101 st_processor_clear_caches (pr);
1103 pr->message_argcount = 0;
1104 pr->message_receiver = st_smalltalk;
1105 pr->message_selector = st_selector_startupSystem;
1107 pr->new_method = st_processor_lookup_method (pr, st_object_class (pr->message_receiver));
1108 st_assert (st_method_get_flags (pr->new_method) == ST_METHOD_NORMAL);
1110 context = method_context_new (pr);
1111 st_processor_set_active_context (pr, context);