Improved speed of JUMP instruction. Previously it tested whether the jump
[panda.git] / src / st-cpu.c
blobe47400f5d2773f0530131acc1827abba9311a4d0
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 inline st_oop
19 method_context_new (void)
21 register struct st_cpu *cpu = &__cpu;
22 st_oop context;
23 st_uint temp_count;
24 st_oop *stack;
25 bool large;
27 large = st_method_get_large_context (cpu->new_method);
28 temp_count = st_method_get_arg_count (cpu->new_method) + st_method_get_temp_count (cpu->new_method);
30 context = st_memory_allocate_context (large);
32 ST_CONTEXT_PART_SENDER (context) = cpu->context;
33 ST_CONTEXT_PART_IP (context) = st_smi_new (0);
34 ST_CONTEXT_PART_SP (context) = st_smi_new (temp_count);
35 ST_METHOD_CONTEXT_RECEIVER (context) = cpu->message_receiver;
36 ST_METHOD_CONTEXT_METHOD (context) = cpu->new_method;
38 /* clear temporaries (and nothing above) */
39 stack = ST_METHOD_CONTEXT_STACK (context);
40 for (st_uint i=0; i < temp_count; i++)
41 stack[i] = ST_NIL;
43 return context;
46 static st_oop
47 block_context_new (st_uint initial_ip, st_uint argcount)
49 register struct st_cpu *cpu = &__cpu;
50 st_oop home;
51 st_oop context;
52 st_oop method;
53 st_oop *stack;
54 st_uint stack_size;
56 stack_size = 32;
58 context = st_memory_allocate (ST_SIZE_OOPS (struct st_block_context) + stack_size);
59 st_object_initialize_header (context, ST_BLOCK_CONTEXT_CLASS);
60 st_object_set_large_context (context, true);
62 if (ST_OBJECT_CLASS (cpu->context) == ST_BLOCK_CONTEXT_CLASS)
63 home = ST_BLOCK_CONTEXT_HOME (cpu->context);
64 else
65 home = cpu->context;
67 ST_CONTEXT_PART_SENDER (context) = ST_NIL;
68 ST_CONTEXT_PART_IP (context) = st_smi_new (0);
69 ST_CONTEXT_PART_SP (context) = st_smi_new (0);
71 ST_BLOCK_CONTEXT_INITIALIP (context) = st_smi_new (initial_ip);
72 ST_BLOCK_CONTEXT_ARGCOUNT (context) = st_smi_new (argcount);
73 ST_BLOCK_CONTEXT_CALLER (context) = ST_NIL;
74 ST_BLOCK_CONTEXT_HOME (context) = home;
76 /* don't nil stack, not needed */
78 return context;
81 static void
82 create_actual_message (void)
84 register struct st_cpu *cpu = &__cpu;
85 st_oop *elements;
86 st_oop message;
87 st_oop array;
89 array = st_object_new_arrayed (ST_ARRAY_CLASS, cpu->message_argcount);
91 elements = st_array_elements (array);
92 for (st_uint i = 0; i < cpu->message_argcount; i++)
93 elements[i] = cpu->stack[cpu->sp - cpu->message_argcount + i];
95 cpu->sp -= cpu->message_argcount;
96 message = st_message_new (cpu->message_selector, array);
97 if (st_memory_compaction_occurred ()) {
98 array = st_memory_remap_reference (array);
101 ST_STACK_PUSH (cpu, message);
103 cpu->message_selector = ST_SELECTOR_DOESNOTUNDERSTAND;
104 cpu->message_argcount = 1;
107 static st_oop
108 lookup_method (st_oop class)
110 register struct st_cpu *cpu = &__cpu;
111 st_oop method;
112 st_oop parent = class;
113 st_uint index;
115 while (parent != ST_NIL) {
116 method = st_dictionary_at (ST_BEHAVIOR_METHOD_DICTIONARY (parent), cpu->message_selector);
117 if (method != ST_NIL)
118 return method;
119 parent = ST_BEHAVIOR_SUPERCLASS (parent);
122 if (cpu->message_selector == ST_SELECTOR_DOESNOTUNDERSTAND) {
123 fprintf (stderr, "panda: error: no method found for #doesNotUnderstand:\n");
124 exit(1);
127 create_actual_message ();
129 return lookup_method (class);
132 st_oop
133 st_cpu_lookup_method (st_oop class)
135 return lookup_method (class);
139 * Creates a new method context. Parameterised by
140 * @sender, @receiver, @method, and @argcount
142 * Message arguments are copied into the new context's temporary
143 * frame. Receiver and arguments are then popped off the stack.
146 static inline void
147 activate_method (void)
149 register struct st_cpu *cpu = &__cpu;
150 st_oop context;
151 st_oop *arguments;
153 context = method_context_new ();
155 arguments = ST_METHOD_CONTEXT_STACK (context);
156 for (st_uint i = 0; i < cpu->message_argcount; i++)
157 arguments[i] = cpu->stack[cpu->sp - cpu->message_argcount + i];
159 cpu->sp -= cpu->message_argcount + 1;
161 st_cpu_set_active_context (context);
164 void
165 st_cpu_execute_method (void)
167 register struct st_cpu *cpu = &__cpu;
168 st_uint primitive_index;
169 st_method_flags flags;
171 flags = st_method_get_flags (cpu->new_method);
172 if (flags == ST_METHOD_PRIMITIVE) {
173 primitive_index = st_method_get_primitive_index (cpu->new_method);
174 cpu->success = true;
175 st_primitives[primitive_index].func (cpu);
176 if (ST_LIKELY (cpu->success))
177 return;
180 activate_method ();
184 void
185 st_cpu_set_active_context (st_oop context)
187 register struct st_cpu *cpu = &__cpu;
188 st_oop home;
190 /* save executation state of active context */
191 if (ST_UNLIKELY (cpu->context != ST_NIL)) {
192 ST_CONTEXT_PART_IP (cpu->context) = st_smi_new (cpu->ip);
193 ST_CONTEXT_PART_SP (cpu->context) = st_smi_new (cpu->sp);
196 if (ST_OBJECT_CLASS (context) == ST_BLOCK_CONTEXT_CLASS) {
197 home = ST_BLOCK_CONTEXT_HOME (context);
198 cpu->method = ST_METHOD_CONTEXT_METHOD (home);
199 cpu->receiver = ST_METHOD_CONTEXT_RECEIVER (home);
200 cpu->literals = st_array_elements (ST_METHOD_LITERALS (cpu->method));
201 cpu->temps = ST_METHOD_CONTEXT_STACK (home);
202 cpu->stack = ST_BLOCK_CONTEXT_STACK (context);
203 } else {
204 cpu->method = ST_METHOD_CONTEXT_METHOD (context);
205 cpu->receiver = ST_METHOD_CONTEXT_RECEIVER (context);
206 cpu->literals = st_array_elements (ST_METHOD_LITERALS (cpu->method));
207 cpu->temps = ST_METHOD_CONTEXT_STACK (context);
208 cpu->stack = ST_METHOD_CONTEXT_STACK (context);
211 cpu->context = context;
212 cpu->sp = st_smi_value (ST_CONTEXT_PART_SP (context));
213 cpu->ip = st_smi_value (ST_CONTEXT_PART_IP (context));
214 cpu->bytecode = st_method_bytecode_bytes (cpu->method);
217 void
218 st_cpu_prologue (void)
220 if (st_verbose_mode ()) {
221 fprintf (stderr, "** gc: totalPauseTime: %.6fs\n", st_timespec_to_double_seconds (&memory->total_pause_time));
225 #define SEND_SELECTOR(selector, argcount) \
226 cpu->message_argcount = argcount; \
227 cpu->message_receiver = sp[- argcount - 1]; \
228 cpu->message_selector = selector; \
229 goto send_common;
231 #define ACTIVATE_CONTEXT(context) \
232 st_cpu_set_active_context (context);
234 #define SEND_TEMPLATE() \
235 cpu->lookup_class = st_object_class (cpu->message_receiver); \
236 ip += 1; \
237 goto common;
239 #ifdef __GNUC__
240 #define HAVE_COMPUTED_GOTO
241 #endif
243 #ifdef HAVE_COMPUTED_GOTO
244 #define SWITCH(ip) \
245 static const st_pointer labels[] = \
247 NULL, \
248 && PUSH_TEMP, && PUSH_INSTVAR, \
249 && PUSH_LITERAL_CONST, && PUSH_LITERAL_VAR, \
251 && STORE_LITERAL_VAR, && STORE_TEMP, && STORE_INSTVAR, \
252 && STORE_POP_LITERAL_VAR, && STORE_POP_TEMP, && STORE_POP_INSTVAR, \
254 && PUSH_SELF, && PUSH_NIL, && PUSH_TRUE, && PUSH_FALSE, && PUSH_INTEGER, \
256 && RETURN_STACK_TOP, && BLOCK_RETURN, \
257 && POP_STACK_TOP, && DUPLICATE_STACK_TOP, \
259 && PUSH_ACTIVE_CONTEXT, && BLOCK_COPY, \
261 && JUMP_TRUE, && JUMP_FALSE, && JUMP, \
263 && SEND, && SEND_SUPER, \
265 && SEND_PLUS, && SEND_MINUS, \
266 && SEND_LT, && SEND_GT, \
267 && SEND_LE, && SEND_GE, \
268 && SEND_EQ, && SEND_NE, \
269 && SEND_MUL, && SEND_DIV, \
270 && SEND_MOD, && SEND_BITSHIFT, \
271 && SEND_BITAND, && SEND_BITOR, \
272 && SEND_BITXOR, \
274 && SEND_AT, && SEND_AT_PUT, \
275 && SEND_SIZE, && SEND_VALUE, \
276 && SEND_VALUE_ARG, && SEND_IDENTITY_EQ, \
277 && SEND_CLASS, && SEND_NEW, \
278 && SEND_NEW_ARG, \
279 }; \
280 goto *labels[*ip];
281 #else
282 #define SWITCH(ip) \
283 start: \
284 switch (*ip)
285 #endif
287 #ifdef HAVE_COMPUTED_GOTO
288 #define CASE(OP) OP:
289 #else
290 #define CASE(OP) case OP:
291 #endif
293 #ifdef HAVE_COMPUTED_GOTO
294 #define NEXT() goto *labels[*ip]
295 #else
296 #define NEXT() goto start
297 #endif
299 static inline void
300 install_method_in_cache (void)
302 register struct st_cpu *cpu = &__cpu;
303 st_uint index;
305 index = ST_METHOD_CACHE_HASH (cpu->lookup_class, cpu->message_selector) & ST_METHOD_CACHE_MASK;
306 cpu->method_cache[index].class = cpu->lookup_class;
307 cpu->method_cache[index].selector = cpu->message_selector;
308 cpu->method_cache[index].method = cpu->new_method;
311 static inline bool
312 lookup_method_in_cache (void)
314 register struct st_cpu *cpu = &__cpu;
315 st_uint index;
317 index = ST_METHOD_CACHE_HASH (cpu->lookup_class, cpu->message_selector) & ST_METHOD_CACHE_MASK;
318 if (cpu->method_cache[index].class == cpu->lookup_class &&
319 cpu->method_cache[index].selector == cpu->message_selector) {
320 cpu->new_method = cpu->method_cache[index].method;
321 return true;
323 return false;
326 #define STACK_POP(oop) (*--sp)
327 #define STACK_PUSH(oop) (*sp++ = (oop))
328 #define STACK_PEEK(oop) (*(sp-1))
329 #define STACK_UNPOP(count) (sp += count)
330 #define STORE_REGISTERS() \
331 cpu->ip = ip - cpu->bytecode; \
332 cpu->sp = sp - cpu->stack;
333 #define LOAD_REGISTERS() \
334 ip = cpu->bytecode + cpu->ip; \
335 sp = cpu->stack + cpu->sp;
337 void
338 st_cpu_main (void)
340 register struct st_cpu *cpu = &__cpu;
341 register const st_uchar *ip;
342 register st_oop *sp = cpu->stack;
344 if (setjmp (cpu->main_loop))
345 goto out;
347 ip = cpu->bytecode + cpu->ip;
349 SWITCH (ip) {
351 CASE (PUSH_TEMP) {
353 STACK_PUSH (cpu->temps[ip[1]]);
355 ip += 2;
356 NEXT ();
359 CASE (PUSH_INSTVAR) {
361 STACK_PUSH (ST_OBJECT_FIELDS (cpu->receiver)[ip[1]]);
363 ip += 2;
364 NEXT ();
367 CASE (STORE_POP_INSTVAR) {
369 ST_OBJECT_FIELDS (cpu->receiver)[ip[1]] = STACK_POP ();
371 ip += 2;
372 NEXT ();
375 CASE (STORE_INSTVAR) {
377 ST_OBJECT_FIELDS (cpu->receiver)[ip[1]] = STACK_PEEK ();
379 ip += 2;
380 NEXT ();
383 CASE (STORE_POP_TEMP) {
385 cpu->temps[ip[1]] = STACK_POP ();
387 ip += 2;
388 NEXT ();
391 CASE (STORE_TEMP) {
393 cpu->temps[ip[1]] = STACK_PEEK ();
395 ip += 2;
396 NEXT ();
399 CASE (STORE_LITERAL_VAR) {
401 ST_ASSOCIATION_VALUE (cpu->literals[ip[1]]) = STACK_PEEK ();
403 ip += 2;
404 NEXT ();
407 CASE (STORE_POP_LITERAL_VAR) {
409 ST_ASSOCIATION_VALUE (cpu->literals[ip[1]]) = STACK_POP ();
411 ip += 2;
412 NEXT ();
415 CASE (PUSH_SELF) {
417 STACK_PUSH (cpu->receiver);
419 ip += 1;
420 NEXT ();
423 CASE (PUSH_TRUE) {
425 STACK_PUSH (ST_TRUE);
427 ip += 1;
428 NEXT ();
431 CASE (PUSH_FALSE) {
433 STACK_PUSH (ST_FALSE);
435 ip += 1;
436 NEXT ();
439 CASE (PUSH_NIL) {
441 STACK_PUSH (ST_NIL);
443 ip += 1;
444 NEXT ();
447 CASE (PUSH_INTEGER) {
449 STACK_PUSH (st_smi_new ((signed char) ip[1]));
451 ip += 2;
452 NEXT ();
455 CASE (PUSH_ACTIVE_CONTEXT) {
457 STACK_PUSH (cpu->context);
459 ip += 1;
460 NEXT ();
463 CASE (PUSH_LITERAL_CONST) {
465 STACK_PUSH (cpu->literals[ip[1]]);
467 ip += 2;
468 NEXT ();
471 CASE (PUSH_LITERAL_VAR) {
473 st_oop var;
475 var = ST_ASSOCIATION_VALUE (cpu->literals[ip[1]]);
477 STACK_PUSH (var);
479 ip += 2;
480 NEXT ();
483 CASE (JUMP_TRUE) {
485 if (STACK_PEEK () == ST_TRUE) {
486 (void) STACK_POP ();
487 ip += *((unsigned short *) (ip + 1)) + 3;
488 } else if (ST_LIKELY (STACK_PEEK () == ST_FALSE)) {
489 (void) STACK_POP ();
490 ip += 3;
491 } else {
492 ip += 3;
493 SEND_SELECTOR (ST_SELECTOR_MUSTBEBOOLEAN, 0);
496 NEXT ();
500 CASE (JUMP_FALSE) {
502 if (STACK_PEEK () == ST_FALSE) {
503 (void) STACK_POP ();
504 ip += *((unsigned short *) (ip + 1)) + 3;
505 } else if (ST_LIKELY (STACK_PEEK () == ST_TRUE)) {
506 (void) STACK_POP ();
507 ip += 3;
508 } else {
509 ip += 3;
510 SEND_SELECTOR (ST_SELECTOR_MUSTBEBOOLEAN, 0);
513 NEXT ();
516 CASE (JUMP) {
518 ip += *((short *) (ip + 1)) + 3;
519 NEXT ();
522 CASE (SEND_PLUS) {
524 st_oop a, b;
526 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
527 st_object_is_smi (sp[-2]))) {
528 b = STACK_POP ();
529 a = STACK_POP ();
530 STACK_PUSH (st_smi_new (st_smi_value (a) + st_smi_value (b)));
531 ip++;
532 NEXT ();
535 cpu->message_argcount = 1;
536 cpu->message_selector = ST_SELECTOR_PLUS;
537 cpu->message_receiver = sp[- cpu->message_argcount - 1];
538 cpu->lookup_class = st_object_class (cpu->message_receiver);
539 ip += 1;
540 goto send_common;
543 CASE (SEND_MINUS) {
545 st_oop a, b;
547 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
548 st_object_is_smi (sp[-2]))) {
549 b = STACK_POP ();
550 a = STACK_POP ();
551 STACK_PUSH (st_smi_new (st_smi_value (a) - st_smi_value (b)));
552 ip++;
553 NEXT ();
556 cpu->message_argcount = 1;
557 cpu->message_selector = ST_SELECTOR_MINUS;
558 cpu->message_receiver = sp[- cpu->message_argcount - 1];
559 cpu->lookup_class = st_object_class (cpu->message_receiver);
560 ip += 1;
561 goto send_common;
564 CASE (SEND_MUL) {
566 st_oop a, b;
568 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
569 st_object_is_smi (sp[-2]))) {
570 b = STACK_POP ();
571 a = STACK_POP ();
572 STACK_PUSH (st_smi_new (st_smi_value (a) * st_smi_value (b)));
573 ip++;
574 NEXT ();
577 cpu->message_argcount = 1;
578 cpu->message_selector = ST_SELECTOR_MUL;
579 cpu->message_receiver = sp[- cpu->message_argcount - 1];
580 cpu->lookup_class = st_object_class (cpu->message_receiver);
581 ip += 1;
582 goto send_common;
586 CASE (SEND_MOD) {
588 st_oop a, b;
590 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
591 st_object_is_smi (sp[-2]))) {
592 b = STACK_POP ();
593 a = STACK_POP ();
594 STACK_PUSH (st_smi_new (st_smi_value (a) % st_smi_value (b)));
595 ip++;
596 NEXT ();
599 cpu->message_argcount = 1;
600 cpu->message_selector = ST_SELECTOR_MOD;
601 cpu->message_receiver = sp[- cpu->message_argcount - 1];
602 cpu->lookup_class = st_object_class (cpu->message_receiver);
603 ip += 1;
604 goto send_common;
607 CASE (SEND_DIV) {
609 cpu->message_argcount = 1;
610 cpu->message_selector = ST_SELECTOR_DIV;
611 cpu->message_receiver = sp[- cpu->message_argcount - 1];
612 cpu->lookup_class = st_object_class (cpu->message_receiver);
613 ip += 1;
614 goto send_common;
617 CASE (SEND_BITSHIFT) {
619 st_oop a, b;
621 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
622 st_object_is_smi (sp[-2]))) {
623 b = STACK_POP ();
624 a = STACK_POP ();
625 if (st_smi_value (b) < 0) {
626 STACK_PUSH (st_smi_new (st_smi_value (a) >> -st_smi_value (b)));
627 } else
628 STACK_PUSH (st_smi_new (st_smi_value (a) << st_smi_value (b)));
629 ip++;
630 NEXT ();
633 cpu->message_argcount = 1;
634 cpu->message_selector = ST_SELECTOR_BITSHIFT;
635 cpu->message_receiver = sp[- cpu->message_argcount - 1];
636 cpu->lookup_class = st_object_class (cpu->message_receiver);
637 ip += 1;
638 goto send_common;
641 CASE (SEND_BITAND) {
643 st_oop a, b;
645 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
646 st_object_is_smi (sp[-2]))) {
647 b = STACK_POP ();
648 a = STACK_POP ();
649 STACK_PUSH (st_smi_new (st_smi_value (a) & st_smi_value (b)));
650 ip++;
651 NEXT ();
654 cpu->message_argcount = 1;
655 cpu->message_selector = ST_SELECTOR_BITAND;
656 cpu->message_receiver = sp[- cpu->message_argcount - 1];
657 cpu->lookup_class = st_object_class (cpu->message_receiver);
658 ip += 1;
659 goto send_common;
662 CASE (SEND_BITOR) {
664 st_oop a, b;
666 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
667 st_object_is_smi (sp[-2]))) {
668 b = STACK_POP ();
669 a = STACK_POP ();
670 STACK_PUSH (st_smi_new (st_smi_value (a) | st_smi_value (b)));
671 ip++;
672 NEXT ();
675 cpu->message_argcount = 1;
676 cpu->message_selector = ST_SELECTOR_BITOR;
677 cpu->message_receiver = sp[- cpu->message_argcount - 1];
678 cpu->lookup_class = st_object_class (cpu->message_receiver);
679 ip += 1;
680 goto send_common;
684 CASE (SEND_BITXOR) {
686 st_oop a, b;
688 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
689 st_object_is_smi (sp[-2]))) {
690 b = STACK_POP ();
691 a = STACK_POP ();
692 STACK_PUSH (st_smi_new (st_smi_value (a) ^ st_smi_value (b)));
693 ip++;
694 NEXT ();
697 cpu->message_argcount = 1;
698 cpu->message_selector = ST_SELECTOR_BITXOR;
699 cpu->message_receiver = sp[- cpu->message_argcount - 1];
700 cpu->lookup_class = st_object_class (cpu->message_receiver);
701 ip += 1;
702 goto send_common;
705 CASE (SEND_LT) {
707 st_oop a, b;
709 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
710 st_object_is_smi (sp[-2]))) {
711 b = STACK_POP ();
712 a = STACK_POP ();
713 STACK_PUSH (st_smi_value (a) < st_smi_value (b) ? ST_TRUE : ST_FALSE);
714 ip++;
715 NEXT ();
718 cpu->message_argcount = 1;
719 cpu->message_selector = ST_SELECTOR_LT;
720 cpu->message_receiver = sp[- cpu->message_argcount - 1];
721 cpu->lookup_class = st_object_class (cpu->message_receiver);
722 ip += 1;
723 goto send_common;
726 CASE (SEND_GT) {
728 st_oop a, b;
730 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
731 st_object_is_smi (sp[-2]))) {
732 b = STACK_POP ();
733 a = STACK_POP ();
734 STACK_PUSH (st_smi_value (a) > st_smi_value (b) ? ST_TRUE : ST_FALSE);
735 ip++;
736 NEXT ();
739 cpu->message_argcount = 1;
740 cpu->message_selector = ST_SELECTOR_GT;
741 cpu->message_receiver = sp[- cpu->message_argcount - 1];
742 cpu->lookup_class = st_object_class (cpu->message_receiver);
743 ip += 1;
744 goto send_common;
748 CASE (SEND_LE) {
750 st_oop a, b;
752 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
753 st_object_is_smi (sp[-2]))) {
754 b = STACK_POP ();
755 a = STACK_POP ();
756 STACK_PUSH (st_smi_value (a) <= st_smi_value (b) ? ST_TRUE : ST_FALSE);
757 ip++;
758 NEXT ();
761 cpu->message_argcount = 1;
762 cpu->message_selector = ST_SELECTOR_LE;
763 cpu->message_receiver = sp[- cpu->message_argcount - 1];
764 cpu->lookup_class = st_object_class (cpu->message_receiver);
765 ip += 1;
766 goto send_common;
769 CASE (SEND_GE) {
771 st_oop a, b;
773 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
774 st_object_is_smi (sp[-2]))) {
775 b = STACK_POP ();
776 a = STACK_POP ();
777 STACK_PUSH (st_smi_value (a) >= st_smi_value (b) ? ST_TRUE : ST_FALSE);
778 ip++;
779 NEXT ();
782 cpu->message_argcount = 1;
783 cpu->message_selector = ST_SELECTOR_GE;
784 cpu->message_receiver = sp[- cpu->message_argcount - 1];
785 cpu->lookup_class = st_object_class (cpu->message_receiver);
786 ip += 1;
787 goto send_common;
791 CASE (SEND_CLASS) {
793 cpu->message_argcount = 0;
794 cpu->message_selector = ST_SELECTOR_CLASS;
795 cpu->message_receiver = sp[- cpu->message_argcount - 1];
796 cpu->lookup_class = st_object_class (cpu->message_receiver);
797 ip += 1;
798 goto send_common;
801 CASE (SEND_SIZE) {
803 cpu->message_argcount = 0;
804 cpu->message_selector = ST_SELECTOR_SIZE;
805 cpu->message_receiver = sp[- cpu->message_argcount - 1];
806 cpu->lookup_class = st_object_class (cpu->message_receiver);
807 ip += 1;
808 goto send_common;
811 CASE (SEND_AT) {
813 st_oop receiver;
814 st_oop integer;
815 st_uint index;
817 integer = STACK_POP ();
818 receiver = STACK_POP ();
819 if (st_object_is_heap (receiver) &&
820 st_object_format (receiver) == ST_FORMAT_ARRAY) {
822 if (ST_LIKELY (st_object_is_smi (integer)))
823 index = st_smi_value (integer);
824 else if (ST_UNLIKELY (st_object_is_character (integer))) {
825 STACK_UNPOP (2);
826 goto common_at;
827 } else if (ST_LIKELY (ST_OBJECT_CLASS (integer) == ST_LARGE_INTEGER_CLASS))
828 index = mp_get_int (st_large_integer_value (integer));
829 else {
830 STACK_UNPOP (2);
831 goto common_at;
834 if (ST_UNLIKELY (index < 1 || index > st_smi_value (st_arrayed_object_size (receiver)))) {
835 STACK_UNPOP (2);
836 goto common_at;
839 STACK_PUSH (st_array_at (receiver, index));
841 ip += 1;
842 NEXT ();
843 } else {
844 STACK_UNPOP (2);
848 common_at:
850 cpu->message_argcount = 1;
851 cpu->message_selector = ST_SELECTOR_AT;
852 cpu->message_receiver = sp[- cpu->message_argcount - 1];
853 cpu->lookup_class = st_object_class (cpu->message_receiver);
854 ip += 1;
855 goto send_common;
858 CASE (SEND_AT_PUT) {
860 st_oop receiver;
861 st_oop integer;
862 st_oop value;
863 st_uint index;
865 value = STACK_POP ();
866 integer = STACK_POP ();
867 receiver = STACK_POP ();
868 if (st_object_is_heap (receiver) &&
869 st_object_format (receiver) == ST_FORMAT_ARRAY) {
871 if (ST_LIKELY (st_object_is_smi (integer))) {
872 index = st_smi_value (integer);
873 } else if (ST_UNLIKELY (st_object_is_character (integer))) {
874 STACK_UNPOP (3);
875 goto common_atput;
876 } else if (ST_LIKELY (ST_OBJECT_CLASS (integer) == ST_LARGE_INTEGER_CLASS)) {
877 index = mp_get_int (st_large_integer_value (integer));
878 } else {
879 STACK_UNPOP (3);
880 goto common_atput;
883 if (ST_UNLIKELY (index < 1 || index > st_smi_value (st_arrayed_object_size (receiver)))) {
884 STACK_UNPOP (3);
885 goto common_atput;
888 st_array_at_put (receiver, index, value);
889 STACK_PUSH (value);
891 ip += 1;
892 NEXT ();
894 } else {
895 STACK_UNPOP (3);
898 common_atput:
900 cpu->message_argcount = 2;
901 cpu->message_selector = ST_SELECTOR_ATPUT;
902 cpu->message_receiver = sp[- cpu->message_argcount - 1];
903 cpu->lookup_class = st_object_class (cpu->message_receiver);
904 ip += 1;
905 goto send_common;
908 CASE (SEND_EQ) {
910 cpu->message_argcount = 1;
911 cpu->message_selector = ST_SELECTOR_EQ;
912 cpu->message_receiver = sp[- cpu->message_argcount - 1];
913 cpu->lookup_class = st_object_class (cpu->message_receiver);
914 ip += 1;
915 goto send_common;
918 CASE (SEND_NE) {
920 cpu->message_argcount = 1;
921 cpu->message_selector = ST_SELECTOR_NE;
922 cpu->message_receiver = sp[- cpu->message_argcount - 1];
923 cpu->lookup_class = st_object_class (cpu->message_receiver);
924 ip += 1;
925 goto send_common;
928 CASE (SEND_IDENTITY_EQ) {
930 st_oop a, b;
931 a = STACK_POP ();
932 b = STACK_POP ();
934 STACK_PUSH ((a == b) ? ST_TRUE : ST_FALSE);
936 ip += 1;
937 NEXT ();
940 CASE (SEND_VALUE) {
942 cpu->message_argcount = 0;
943 cpu->message_selector = ST_SELECTOR_VALUE;
944 cpu->message_receiver = sp[- cpu->message_argcount - 1];
945 cpu->lookup_class = st_object_class (cpu->message_receiver);
946 ip += 1;
947 goto send_common;
950 CASE (SEND_VALUE_ARG) {
952 cpu->message_argcount = 1;
953 cpu->message_selector = ST_SELECTOR_VALUE_ARG;
954 cpu->message_receiver = sp[- cpu->message_argcount - 1];
955 cpu->lookup_class = st_object_class (cpu->message_receiver);
956 ip += 1;
957 goto send_common;
960 CASE (SEND_NEW) {
962 cpu->message_argcount = 0;
963 cpu->message_selector = ST_SELECTOR_NEW;
964 cpu->message_receiver = sp[- cpu->message_argcount - 1];
965 cpu->lookup_class = st_object_class (cpu->message_receiver);
966 ip += 1;
967 goto send_common;
970 CASE (SEND_NEW_ARG) {
972 cpu->message_argcount = 1;
973 cpu->message_selector = ST_SELECTOR_NEW_ARG;
974 cpu->message_receiver = sp[- cpu->message_argcount - 1];
975 cpu->lookup_class = st_object_class (cpu->message_receiver);
976 ip += 1;
977 goto send_common;
980 CASE (SEND) {
982 st_uint primitive_index;
983 st_method_flags flags;
984 st_oop context;
985 st_oop *arguments;
987 cpu->message_argcount = ip[1];
988 cpu->message_selector = cpu->literals[ip[2]];
989 cpu->message_receiver = sp[- cpu->message_argcount - 1];
990 cpu->lookup_class = st_object_class (cpu->message_receiver);
991 ip += 3;
993 send_common:
995 if (!lookup_method_in_cache ()) {
996 STORE_REGISTERS ();
997 cpu->new_method = lookup_method (cpu->lookup_class);
998 LOAD_REGISTERS ();
999 install_method_in_cache ();
1002 flags = st_method_get_flags (cpu->new_method);
1003 if (flags == ST_METHOD_PRIMITIVE) {
1004 primitive_index = st_method_get_primitive_index (cpu->new_method);
1006 cpu->success = true;
1007 STORE_REGISTERS ();
1008 st_primitives[primitive_index].func (cpu);
1009 LOAD_REGISTERS ();
1011 if (ST_LIKELY (cpu->success))
1012 NEXT ();
1015 context = method_context_new ();
1016 arguments = ST_METHOD_CONTEXT_STACK (context);
1017 for (int i = 0; i < cpu->message_argcount; i++)
1018 arguments[i] = sp[- cpu->message_argcount + i];
1019 sp -= cpu->message_argcount + 1;
1021 ST_CONTEXT_PART_IP (cpu->context) = st_smi_new (ip - cpu->bytecode);
1022 ST_CONTEXT_PART_SP (cpu->context) = st_smi_new (sp - cpu->stack);
1023 cpu->context = context;
1024 cpu->method = ST_METHOD_CONTEXT_METHOD (context);
1025 cpu->receiver = ST_METHOD_CONTEXT_RECEIVER (context);
1026 cpu->literals = st_array_elements (ST_METHOD_LITERALS (cpu->method));
1027 cpu->temps = ST_METHOD_CONTEXT_STACK (context);
1028 cpu->stack = ST_METHOD_CONTEXT_STACK (context);
1029 cpu->sp = st_smi_value (ST_CONTEXT_PART_SP (context));
1030 cpu->ip = st_smi_value (0);
1031 cpu->bytecode = st_method_bytecode_bytes (cpu->method);
1032 LOAD_REGISTERS ();
1034 /* We have to nil these fields here. Its possible that
1035 that the objects they reference may be zapped by the gc.
1036 Another GC invocation may try to remap these fields not knowing that
1037 the references are invalid.
1038 FIXME: move this nilling out of such a critical execution path */
1039 cpu->message_receiver = ST_NIL;
1040 cpu->message_selector = ST_NIL;
1042 NEXT ();
1045 CASE (SEND_SUPER) {
1047 st_oop index;
1049 cpu->message_argcount = ip[1];
1050 cpu->message_selector = cpu->literals[ip[2]];
1051 cpu->message_receiver = sp[- cpu->message_argcount - 1];
1053 index = st_smi_value (st_arrayed_object_size (ST_METHOD_LITERALS (cpu->method))) - 1;
1054 cpu->lookup_class = ST_BEHAVIOR_SUPERCLASS (cpu->literals[index]);
1056 ip += 3;
1058 goto send_common;
1061 CASE (POP_STACK_TOP) {
1063 (void) STACK_POP ();
1065 ip += 1;
1066 NEXT ();
1069 CASE (DUPLICATE_STACK_TOP) {
1071 STACK_PUSH (STACK_PEEK ());
1073 ip += 1;
1074 NEXT ();
1077 CASE (BLOCK_COPY) {
1079 st_oop block;
1080 st_oop home;
1081 st_uint argcount = ip[1];
1082 st_uint initial_ip;
1084 ip += 2;
1086 initial_ip = ip - cpu->bytecode + 3;
1088 STORE_REGISTERS ();
1089 block = block_context_new (initial_ip, argcount);
1090 LOAD_REGISTERS ();
1092 STACK_PUSH (block);
1094 NEXT ();
1097 CASE (RETURN_STACK_TOP) {
1099 st_oop sender;
1100 st_oop value;
1101 st_oop home;
1103 value = STACK_PEEK ();
1105 if (ST_OBJECT_CLASS (cpu->context) == ST_BLOCK_CONTEXT_CLASS)
1106 sender = ST_CONTEXT_PART_SENDER (ST_BLOCK_CONTEXT_HOME (cpu->context));
1107 else {
1108 sender = ST_CONTEXT_PART_SENDER (cpu->context);
1109 st_memory_recycle_context (cpu->context);
1112 if (ST_UNLIKELY (sender == ST_NIL)) {
1113 STACK_PUSH (cpu->context);
1114 STACK_PUSH (value);
1115 SEND_SELECTOR (ST_SELECTOR_CANNOTRETURN, 1);
1116 NEXT ();
1119 if (ST_OBJECT_CLASS (sender) == ST_BLOCK_CONTEXT_CLASS) {
1120 home = ST_BLOCK_CONTEXT_HOME (sender);
1121 cpu->method = ST_METHOD_CONTEXT_METHOD (home);
1122 cpu->receiver = ST_METHOD_CONTEXT_RECEIVER (home);
1123 cpu->literals = st_array_elements (ST_METHOD_LITERALS (cpu->method));
1124 cpu->temps = ST_METHOD_CONTEXT_STACK (home);
1125 cpu->stack = ST_BLOCK_CONTEXT_STACK (sender);
1126 } else {
1127 cpu->method = ST_METHOD_CONTEXT_METHOD (sender);
1128 cpu->receiver = ST_METHOD_CONTEXT_RECEIVER (sender);
1129 cpu->literals = st_array_elements (ST_METHOD_LITERALS (cpu->method));
1130 cpu->temps = ST_METHOD_CONTEXT_STACK (sender);
1131 cpu->stack = ST_METHOD_CONTEXT_STACK (sender);
1134 cpu->context = sender;
1135 cpu->sp = st_smi_value (ST_CONTEXT_PART_SP (sender));
1136 cpu->ip = st_smi_value (ST_CONTEXT_PART_IP (sender));
1137 cpu->bytecode = st_method_bytecode_bytes (cpu->method);
1138 LOAD_REGISTERS ();
1140 STACK_PUSH (value);
1142 NEXT ();
1145 CASE (BLOCK_RETURN) {
1147 st_oop caller;
1148 st_oop value;
1149 st_oop home;
1151 caller = ST_BLOCK_CONTEXT_CALLER (cpu->context);
1152 value = STACK_PEEK ();
1154 if (ST_OBJECT_CLASS (caller) == ST_BLOCK_CONTEXT_CLASS) {
1155 home = ST_BLOCK_CONTEXT_HOME (caller);
1156 cpu->method = ST_METHOD_CONTEXT_METHOD (home);
1157 cpu->receiver = ST_METHOD_CONTEXT_RECEIVER (home);
1158 cpu->literals = st_array_elements (ST_METHOD_LITERALS (cpu->method));
1159 cpu->temps = ST_METHOD_CONTEXT_STACK (home);
1160 cpu->stack = ST_BLOCK_CONTEXT_STACK (caller);
1161 } else {
1162 cpu->method = ST_METHOD_CONTEXT_METHOD (caller);
1163 cpu->receiver = ST_METHOD_CONTEXT_RECEIVER (caller);
1164 cpu->literals = st_array_elements (ST_METHOD_LITERALS (cpu->method));
1165 cpu->temps = ST_METHOD_CONTEXT_STACK (caller);
1166 cpu->stack = ST_METHOD_CONTEXT_STACK (caller);
1169 cpu->context = caller;
1170 cpu->sp = st_smi_value (ST_CONTEXT_PART_SP (caller));
1171 cpu->ip = st_smi_value (ST_CONTEXT_PART_IP (caller));
1172 cpu->bytecode = st_method_bytecode_bytes (cpu->method);
1173 LOAD_REGISTERS ();
1175 /* push returned value onto caller's stack */
1176 STACK_PUSH (value);
1178 NEXT ();
1182 out:
1183 st_cpu_prologue ();
1186 void
1187 st_cpu_clear_caches (void)
1189 memset (__cpu.method_cache, 0, ST_METHOD_CACHE_SIZE * 3 * sizeof (st_oop));
1192 void
1193 st_cpu_initialize (void)
1195 st_oop context;
1196 st_oop method;
1198 /* clear contents */
1199 __cpu.context = ST_NIL;
1200 __cpu.receiver = ST_NIL;
1201 __cpu.method = ST_NIL;
1203 __cpu.sp = 0;
1204 __cpu.ip = 0;
1205 __cpu.stack = NULL;
1207 st_cpu_clear_caches ();
1209 __cpu.message_argcount = 0;
1210 __cpu.message_receiver = ST_SMALLTALK;
1211 __cpu.message_selector = ST_SELECTOR_STARTUPSYSTEM;
1213 __cpu.new_method = lookup_method (st_object_class (__cpu.message_receiver));
1214 st_assert (st_method_get_flags (__cpu.new_method) == ST_METHOD_NORMAL);
1216 context = method_context_new ();
1217 st_cpu_set_active_context (context);