Removed the notion of a "large" context. For simplicity, all contexts
[panda.git] / src / st-machine.c
blob09deea09d927350ea6106e5e4eda41ebf0da54b3
1 /*
2 * st-machine.c
4 * Copyright (C) 2008 Vincent Geddes
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
25 #include "st-types.h"
26 #include "st-compiler.h"
27 #include "st-universe.h"
28 #include "st-dictionary.h"
29 #include "st-symbol.h"
30 #include "st-object.h"
31 #include "st-behavior.h"
32 #include "st-context.h"
33 #include "st-primitives.h"
34 #include "st-method.h"
35 #include "st-array.h"
36 #include "st-association.h"
37 #include "st-memory.h"
39 #include <stdlib.h>
40 #include <setjmp.h>
42 #ifdef __GNUC__
43 #define HAVE_COMPUTED_GOTO
44 #endif
46 static inline st_oop
47 method_context_new (st_machine *machine)
49 st_oop context;
50 st_uint temp_count;
51 st_oop *stack;
52 bool large;
54 temp_count = st_method_get_arg_count (machine->new_method) + st_method_get_temp_count (machine->new_method);
56 context = st_memory_allocate_context ();
58 ST_CONTEXT_PART_SENDER (context) = machine->context;
59 ST_CONTEXT_PART_IP (context) = st_smi_new (0);
60 ST_CONTEXT_PART_SP (context) = st_smi_new (temp_count);
61 ST_METHOD_CONTEXT_RECEIVER (context) = machine->message_receiver;
62 ST_METHOD_CONTEXT_METHOD (context) = machine->new_method;
64 /* clear temporaries (and nothing above) */
65 stack = ST_METHOD_CONTEXT_STACK (context);
66 for (st_uint i=0; i < temp_count; i++)
67 stack[i] = ST_NIL;
69 return context;
72 static st_oop
73 block_context_new (st_machine *machine, st_uint initial_ip, st_uint argcount)
75 st_oop home;
76 st_oop context;
77 st_oop method;
78 st_oop *stack;
79 st_uint stack_size;
81 stack_size = 32;
83 context = st_memory_allocate (ST_SIZE_OOPS (struct st_block_context) + stack_size);
84 if (context == 0) {
85 st_memory_perform_gc ();
86 context = st_memory_allocate (ST_SIZE_OOPS (struct st_block_context) + stack_size);
87 st_assert (context != 0);
90 st_object_initialize_header (context, ST_BLOCK_CONTEXT_CLASS);
92 if (ST_OBJECT_CLASS (machine->context) == ST_BLOCK_CONTEXT_CLASS)
93 home = ST_BLOCK_CONTEXT_HOME (machine->context);
94 else
95 home = machine->context;
97 ST_CONTEXT_PART_SENDER (context) = ST_NIL;
98 ST_CONTEXT_PART_IP (context) = st_smi_new (0);
99 ST_CONTEXT_PART_SP (context) = st_smi_new (0);
101 ST_BLOCK_CONTEXT_INITIALIP (context) = st_smi_new (initial_ip);
102 ST_BLOCK_CONTEXT_ARGCOUNT (context) = st_smi_new (argcount);
103 ST_BLOCK_CONTEXT_HOME (context) = home;
105 return context;
108 static void
109 create_actual_message (st_machine *machine)
111 st_oop *elements;
112 st_oop message;
113 st_oop array;
115 array = st_object_new_arrayed (ST_ARRAY_CLASS, machine->message_argcount);
116 elements = st_array_elements (array);
117 for (st_uint i = 0; i < machine->message_argcount; i++)
118 elements[i] = machine->stack[machine->sp - machine->message_argcount + i];
120 machine->sp -= machine->message_argcount;
122 message = st_object_new (ST_MESSAGE_CLASS);
123 if (message == 0) {
124 st_memory_perform_gc ();
125 message = st_object_new (ST_MESSAGE_CLASS);
126 st_assert (message != 0);
129 ST_OBJECT_FIELDS (message)[0] = machine->message_selector;
130 ST_OBJECT_FIELDS (message)[1] = array;
132 ST_STACK_PUSH (machine, message);
134 machine->message_selector = ST_SELECTOR_DOESNOTUNDERSTAND;
135 machine->message_argcount = 1;
138 static st_oop
139 lookup_method (st_machine *machine, st_oop class)
141 st_oop method, dict, parent;
142 st_uint hash;
144 parent = class;
145 hash = st_byte_array_hash (machine->message_selector);
147 while (parent != ST_NIL) {
149 st_oop el;
150 st_uint mask, i;
152 dict = ST_BEHAVIOR_METHOD_DICTIONARY (parent);
153 mask = st_smi_value (st_arrayed_object_size (ST_OBJECT_FIELDS (dict)[2])) - 1;
154 i = (hash & mask) + 1;
156 while (true) {
157 el = st_array_at (ST_OBJECT_FIELDS (dict)[2], i);
158 if (el == ST_NIL || el == (uintptr_t) ST_OBJECT_FIELDS (dict)[2])
159 break;
160 if (machine->message_selector == ST_ASSOCIATION_KEY (el))
161 return ST_ASSOCIATION_VALUE (el);
162 i = ((i + ST_ADVANCE_SIZE) & mask) + 1;
165 parent = ST_BEHAVIOR_SUPERCLASS (parent);
168 if (machine->message_selector == ST_SELECTOR_DOESNOTUNDERSTAND) {
169 fprintf (stderr, "panda: error: no method found for #doesNotUnderstand:\n");
170 exit(1);
173 create_actual_message (machine);
175 return lookup_method (machine, class);
178 st_oop
179 st_machine_lookup_method (st_machine *machine, st_oop class)
181 return lookup_method (machine, class);
185 * Creates a new method context. Parameterised by
186 * @sender, @receiver, @method, and @argcount
188 * Message arguments are copied into the new context's temporary
189 * frame. Receiver and arguments are then popped off the stack.
192 static inline void
193 activate_method (st_machine *machine)
195 st_oop context;
196 st_oop *arguments;
198 context = method_context_new (machine);
200 arguments = ST_METHOD_CONTEXT_STACK (context);
201 for (st_uint i = 0; i < machine->message_argcount; i++)
202 arguments[i] = machine->stack[machine->sp - machine->message_argcount + i];
204 machine->sp -= machine->message_argcount + 1;
206 st_machine_set_active_context (machine, context);
209 void
210 st_machine_execute_method (st_machine *machine)
212 st_uint primitive_index;
213 st_method_flags flags;
215 flags = st_method_get_flags (machine->new_method);
216 if (flags == ST_METHOD_PRIMITIVE) {
217 primitive_index = st_method_get_primitive_index (machine->new_method);
218 machine->success = true;
219 st_primitives[primitive_index].func (machine);
220 if (ST_LIKELY (machine->success))
221 return;
224 activate_method (machine);
227 void
228 st_machine_set_active_context (st_machine *machine, st_oop context)
230 st_oop home;
232 /* save executation state of active context */
233 if (ST_UNLIKELY (machine->context != ST_NIL)) {
234 ST_CONTEXT_PART_IP (machine->context) = st_smi_new (machine->ip);
235 ST_CONTEXT_PART_SP (machine->context) = st_smi_new (machine->sp);
238 if (ST_OBJECT_CLASS (context) == ST_BLOCK_CONTEXT_CLASS) {
239 home = ST_BLOCK_CONTEXT_HOME (context);
240 machine->method = ST_METHOD_CONTEXT_METHOD (home);
241 machine->receiver = ST_METHOD_CONTEXT_RECEIVER (home);
242 machine->temps = ST_METHOD_CONTEXT_STACK (home);
243 machine->stack = ST_BLOCK_CONTEXT_STACK (context);
244 } else {
245 machine->method = ST_METHOD_CONTEXT_METHOD (context);
246 machine->receiver = ST_METHOD_CONTEXT_RECEIVER (context);
247 machine->temps = ST_METHOD_CONTEXT_STACK (context);
248 machine->stack = ST_METHOD_CONTEXT_STACK (context);
251 machine->context = context;
252 machine->sp = st_smi_value (ST_CONTEXT_PART_SP (context));
253 machine->ip = st_smi_value (ST_CONTEXT_PART_IP (context));
254 machine->bytecode = st_method_bytecode_bytes (machine->method);
257 #define SEND_SELECTOR(selector, argcount) \
258 machine->message_argcount = argcount; \
259 machine->message_receiver = sp[- argcount - 1]; \
260 machine->message_selector = selector; \
261 goto send_common;
263 #define SEND_TEMPLATE() \
264 machine->lookup_class = st_object_class (machine->message_receiver); \
265 ip += 1; \
266 goto common;
268 #ifdef HAVE_COMPUTED_GOTO
269 #define SWITCH(ip) \
270 static const st_pointer labels[] = \
272 && PUSH_TEMP, \
273 && PUSH_INSTVAR, \
274 && PUSH_LITERAL_CONST, \
275 && PUSH_LITERAL_VAR, \
276 && STORE_LITERAL_VAR, \
277 && STORE_TEMP, \
278 && STORE_INSTVAR, \
279 && STORE_POP_LITERAL_VAR, \
280 && STORE_POP_TEMP, \
281 && STORE_POP_INSTVAR, \
282 && PUSH_SELF, \
283 && PUSH_NIL, \
284 && PUSH_TRUE, \
285 && PUSH_FALSE, \
286 && PUSH_INTEGER, \
287 && RETURN_STACK_TOP, \
288 && BLOCK_RETURN, \
289 && POP_STACK_TOP, \
290 && DUPLICATE_STACK_TOP, \
291 && PUSH_ACTIVE_CONTEXT, \
292 && BLOCK_COPY, \
293 && JUMP_TRUE, \
294 && JUMP_FALSE, \
295 && JUMP, \
296 && SEND, \
297 && SEND_SUPER, \
298 && SEND_PLUS, \
299 && SEND_MINUS, \
300 && SEND_LT, \
301 && SEND_GT, \
302 && SEND_LE, \
303 && SEND_GE, \
304 && SEND_EQ, \
305 && SEND_NE, \
306 && SEND_MUL, \
307 && SEND_DIV, \
308 && SEND_MOD, \
309 && SEND_BITSHIFT, \
310 && SEND_BITAND, \
311 && SEND_BITOR, \
312 && SEND_BITXOR, \
313 && SEND_AT, \
314 && SEND_AT_PUT, \
315 && SEND_SIZE, \
316 && SEND_VALUE, \
317 && SEND_VALUE_ARG, \
318 && SEND_IDENTITY_EQ, \
319 && SEND_CLASS, \
320 && SEND_NEW, \
321 && SEND_NEW_ARG, \
322 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
323 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
324 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
325 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
326 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
327 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
328 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
329 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
330 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
331 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
332 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
333 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
334 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
335 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
336 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
337 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
338 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
339 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
340 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
341 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
342 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
343 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
344 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
345 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
346 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
347 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
348 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
349 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
350 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
351 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
352 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
353 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
354 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
355 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
356 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
357 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
358 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
359 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
360 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
361 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
362 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
363 && INVALID, \
364 }; \
365 goto *labels[*ip];
366 #else
367 #define SWITCH(ip) \
368 start: \
369 switch (*ip)
370 #endif
372 #ifdef HAVE_COMPUTED_GOTO
373 #define INVALID() INVALID:
374 #define CASE(OP) OP:
375 #else
376 #define INVALID() default:
377 #define CASE(OP) case OP:
378 #endif
380 #ifdef HAVE_COMPUTED_GOTO
381 #define NEXT() goto *labels[*ip]
382 #else
383 #define NEXT() goto start
384 #endif
386 static inline void
387 install_method_in_cache (st_machine *machine)
389 st_uint index;
391 index = ST_METHOD_CACHE_HASH (machine->lookup_class, machine->message_selector) & ST_METHOD_CACHE_MASK;
392 machine->method_cache[index].class = machine->lookup_class;
393 machine->method_cache[index].selector = machine->message_selector;
394 machine->method_cache[index].method = machine->new_method;
397 static inline bool
398 lookup_method_in_cache (st_machine *machine)
400 st_uint index;
402 index = ST_METHOD_CACHE_HASH (machine->lookup_class, machine->message_selector) & ST_METHOD_CACHE_MASK;
403 if (machine->method_cache[index].class == machine->lookup_class &&
404 machine->method_cache[index].selector == machine->message_selector) {
405 machine->new_method = machine->method_cache[index].method;
406 return true;
408 return false;
411 #define STACK_POP(oop) (*--sp)
412 #define STACK_PUSH(oop) (*sp++ = (oop))
413 #define STACK_PEEK(oop) (*(sp-1))
414 #define STACK_UNPOP(count) (sp += count)
415 #define STORE_REGISTERS() \
416 machine->ip = ip - machine->bytecode; \
417 machine->sp = sp - machine->stack; \
418 ST_CONTEXT_PART_IP (machine->context) = st_smi_new (machine->ip);
419 #define LOAD_REGISTERS() \
420 ip = machine->bytecode + machine->ip; \
421 sp = machine->stack + machine->sp; \
422 ST_CONTEXT_PART_SP (machine->context) = st_smi_new (machine->sp);
424 void
425 st_machine_main (st_machine *machine)
427 register const st_uchar *ip;
428 register st_oop *sp = machine->stack;
430 if (setjmp (machine->main_loop))
431 goto out;
433 ip = machine->bytecode + machine->ip;
435 SWITCH (ip) {
437 CASE (PUSH_TEMP) {
439 STACK_PUSH (machine->temps[ip[1]]);
441 ip += 2;
442 NEXT ();
445 CASE (PUSH_INSTVAR) {
447 STACK_PUSH (ST_OBJECT_FIELDS (machine->receiver)[ip[1]]);
449 ip += 2;
450 NEXT ();
453 CASE (STORE_POP_INSTVAR) {
455 ST_OBJECT_FIELDS (machine->receiver)[ip[1]] = STACK_POP ();
457 ip += 2;
458 NEXT ();
461 CASE (STORE_INSTVAR) {
463 ST_OBJECT_FIELDS (machine->receiver)[ip[1]] = STACK_PEEK ();
465 ip += 2;
466 NEXT ();
469 CASE (STORE_POP_TEMP) {
471 machine->temps[ip[1]] = STACK_POP ();
473 ip += 2;
474 NEXT ();
477 CASE (STORE_TEMP) {
479 machine->temps[ip[1]] = STACK_PEEK ();
481 ip += 2;
482 NEXT ();
485 CASE (STORE_LITERAL_VAR) {
488 ST_ASSOCIATION_VALUE (st_array_elements (ST_METHOD_LITERALS (machine->method))[ip[1]]) = STACK_PEEK ();
490 ip += 2;
491 NEXT ();
494 CASE (STORE_POP_LITERAL_VAR) {
496 ST_ASSOCIATION_VALUE (st_array_elements (ST_METHOD_LITERALS (machine->method))[ip[1]]) = STACK_POP ();
498 ip += 2;
499 NEXT ();
502 CASE (PUSH_SELF) {
504 STACK_PUSH (machine->receiver);
506 ip += 1;
507 NEXT ();
510 CASE (PUSH_TRUE) {
512 STACK_PUSH (ST_TRUE);
514 ip += 1;
515 NEXT ();
518 CASE (PUSH_FALSE) {
520 STACK_PUSH (ST_FALSE);
522 ip += 1;
523 NEXT ();
526 CASE (PUSH_NIL) {
528 STACK_PUSH (ST_NIL);
530 ip += 1;
531 NEXT ();
534 CASE (PUSH_INTEGER) {
536 STACK_PUSH (st_smi_new ((signed char) ip[1]));
538 ip += 2;
539 NEXT ();
542 CASE (PUSH_ACTIVE_CONTEXT) {
544 STACK_PUSH (machine->context);
546 ip += 1;
547 NEXT ();
550 CASE (PUSH_LITERAL_CONST) {
552 STACK_PUSH (st_array_elements (ST_METHOD_LITERALS (machine->method))[ip[1]]);
554 ip += 2;
555 NEXT ();
558 CASE (PUSH_LITERAL_VAR) {
560 st_oop var;
562 var = ST_ASSOCIATION_VALUE (st_array_elements (ST_METHOD_LITERALS (machine->method))[ip[1]]);
564 STACK_PUSH (var);
566 ip += 2;
567 NEXT ();
570 CASE (JUMP_TRUE) {
572 if (STACK_PEEK () == ST_TRUE) {
573 (void) STACK_POP ();
574 ip += *((unsigned short *) (ip + 1)) + 3;
575 } else if (ST_LIKELY (STACK_PEEK () == ST_FALSE)) {
576 (void) STACK_POP ();
577 ip += 3;
578 } else {
579 ip += 3;
580 SEND_SELECTOR (ST_SELECTOR_MUSTBEBOOLEAN, 0);
583 NEXT ();
587 CASE (JUMP_FALSE) {
589 if (STACK_PEEK () == ST_FALSE) {
590 (void) STACK_POP ();
591 ip += *((unsigned short *) (ip + 1)) + 3;
592 } else if (ST_LIKELY (STACK_PEEK () == ST_TRUE)) {
593 (void) STACK_POP ();
594 ip += 3;
595 } else {
596 ip += 3;
597 SEND_SELECTOR (ST_SELECTOR_MUSTBEBOOLEAN, 0);
600 NEXT ();
603 CASE (JUMP) {
605 ip += *((short *) (ip + 1)) + 3;
606 NEXT ();
609 CASE (SEND_PLUS) {
611 int a, b, result;
613 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
614 st_object_is_smi (sp[-2]))) {
615 b = st_smi_value (sp[-1]);
616 a = st_smi_value (sp[-2]);
617 result = a + b;
618 if (((result << 1) ^ (result << 2)) >= 0) {
619 sp -= 2;
620 STACK_PUSH (st_smi_new (result));
621 ip++;
622 NEXT ();
626 machine->message_argcount = 1;
627 machine->message_selector = ST_SELECTOR_PLUS;
628 machine->message_receiver = sp[- machine->message_argcount - 1];
629 machine->lookup_class = st_object_class (machine->message_receiver);
630 ip += 1;
631 goto send_common;
634 CASE (SEND_MINUS) {
636 int a, b, result;
638 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
639 st_object_is_smi (sp[-2]))) {
640 b = st_smi_value (sp[-1]);
641 a = st_smi_value (sp[-2]);
642 result = a - b;
643 if (((result << 1) ^ (result << 2)) >= 0) {
644 sp -= 2;
645 STACK_PUSH (st_smi_new (result));
646 ip++;
647 NEXT ();
648 } else {
649 STACK_UNPOP (2);
653 machine->message_argcount = 1;
654 machine->message_selector = ST_SELECTOR_MINUS;
655 machine->message_receiver = sp[- machine->message_argcount - 1];
656 machine->lookup_class = st_object_class (machine->message_receiver);
657 ip += 1;
658 goto send_common;
661 CASE (SEND_MUL) {
663 int a, b;
664 int64_t result;
666 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
667 st_object_is_smi (sp[-2]))) {
668 b = st_smi_value (sp[-1]);
669 a = st_smi_value (sp[-2]);
670 result = a * b;
671 if (result >= ST_SMALL_INTEGER_MIN && result <= ST_SMALL_INTEGER_MAX) {
672 sp -= 2;
673 STACK_PUSH (st_smi_new ((int)result));
674 ip++;
675 NEXT ();
679 machine->message_argcount = 1;
680 machine->message_selector = ST_SELECTOR_MUL;
681 machine->message_receiver = sp[- machine->message_argcount - 1];
682 machine->lookup_class = st_object_class (machine->message_receiver);
683 ip += 1;
684 goto send_common;
688 CASE (SEND_MOD) {
690 st_oop a, b;
692 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
693 st_object_is_smi (sp[-2]))) {
694 b = STACK_POP ();
695 a = STACK_POP ();
696 STACK_PUSH (st_smi_new (st_smi_value (a) % st_smi_value (b)));
697 ip++;
698 NEXT ();
701 machine->message_argcount = 1;
702 machine->message_selector = ST_SELECTOR_MOD;
703 machine->message_receiver = sp[- machine->message_argcount - 1];
704 machine->lookup_class = st_object_class (machine->message_receiver);
705 ip += 1;
706 goto send_common;
709 CASE (SEND_DIV) {
711 machine->message_argcount = 1;
712 machine->message_selector = ST_SELECTOR_DIV;
713 machine->message_receiver = sp[- machine->message_argcount - 1];
714 machine->lookup_class = st_object_class (machine->message_receiver);
715 ip += 1;
716 goto send_common;
719 CASE (SEND_BITSHIFT) {
721 st_oop a, b;
723 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
724 st_object_is_smi (sp[-2]))) {
725 b = STACK_POP ();
726 a = STACK_POP ();
727 if (st_smi_value (b) < 0) {
728 STACK_PUSH (st_smi_new (st_smi_value (a) >> -st_smi_value (b)));
729 } else
730 STACK_PUSH (st_smi_new (st_smi_value (a) << st_smi_value (b)));
731 ip++;
732 NEXT ();
735 machine->message_argcount = 1;
736 machine->message_selector = ST_SELECTOR_BITSHIFT;
737 machine->message_receiver = sp[- machine->message_argcount - 1];
738 machine->lookup_class = st_object_class (machine->message_receiver);
739 ip += 1;
740 goto send_common;
743 CASE (SEND_BITAND) {
745 st_oop a, b;
747 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
748 st_object_is_smi (sp[-2]))) {
749 b = STACK_POP ();
750 a = STACK_POP ();
751 STACK_PUSH (st_smi_new (st_smi_value (a) & st_smi_value (b)));
752 ip++;
753 NEXT ();
756 machine->message_argcount = 1;
757 machine->message_selector = ST_SELECTOR_BITAND;
758 machine->message_receiver = sp[- machine->message_argcount - 1];
759 machine->lookup_class = st_object_class (machine->message_receiver);
760 ip += 1;
761 goto send_common;
764 CASE (SEND_BITOR) {
766 st_oop a, b;
768 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
769 st_object_is_smi (sp[-2]))) {
770 b = STACK_POP ();
771 a = STACK_POP ();
772 STACK_PUSH (st_smi_new (st_smi_value (a) | st_smi_value (b)));
773 ip++;
774 NEXT ();
777 machine->message_argcount = 1;
778 machine->message_selector = ST_SELECTOR_BITOR;
779 machine->message_receiver = sp[- machine->message_argcount - 1];
780 machine->lookup_class = st_object_class (machine->message_receiver);
781 ip += 1;
782 goto send_common;
786 CASE (SEND_BITXOR) {
788 st_oop a, b;
790 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
791 st_object_is_smi (sp[-2]))) {
792 b = STACK_POP ();
793 a = STACK_POP ();
794 STACK_PUSH (st_smi_new (st_smi_value (a) ^ st_smi_value (b)));
795 ip++;
796 NEXT ();
799 machine->message_argcount = 1;
800 machine->message_selector = ST_SELECTOR_BITXOR;
801 machine->message_receiver = sp[- machine->message_argcount - 1];
802 machine->lookup_class = st_object_class (machine->message_receiver);
803 ip += 1;
804 goto send_common;
807 CASE (SEND_LT) {
809 st_oop a, b;
811 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
812 st_object_is_smi (sp[-2]))) {
813 b = STACK_POP ();
814 a = STACK_POP ();
815 STACK_PUSH (st_smi_value (a) < st_smi_value (b) ? ST_TRUE : ST_FALSE);
816 ip++;
817 NEXT ();
820 machine->message_argcount = 1;
821 machine->message_selector = ST_SELECTOR_LT;
822 machine->message_receiver = sp[- machine->message_argcount - 1];
823 machine->lookup_class = st_object_class (machine->message_receiver);
824 ip += 1;
825 goto send_common;
828 CASE (SEND_GT) {
830 st_oop a, b;
832 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
833 st_object_is_smi (sp[-2]))) {
834 b = STACK_POP ();
835 a = STACK_POP ();
836 STACK_PUSH (st_smi_value (a) > st_smi_value (b) ? ST_TRUE : ST_FALSE);
837 ip++;
838 NEXT ();
841 machine->message_argcount = 1;
842 machine->message_selector = ST_SELECTOR_GT;
843 machine->message_receiver = sp[- machine->message_argcount - 1];
844 machine->lookup_class = st_object_class (machine->message_receiver);
845 ip += 1;
846 goto send_common;
850 CASE (SEND_LE) {
852 st_oop a, b;
854 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
855 st_object_is_smi (sp[-2]))) {
856 b = STACK_POP ();
857 a = STACK_POP ();
858 STACK_PUSH (st_smi_value (a) <= st_smi_value (b) ? ST_TRUE : ST_FALSE);
859 ip++;
860 NEXT ();
863 machine->message_argcount = 1;
864 machine->message_selector = ST_SELECTOR_LE;
865 machine->message_receiver = sp[- machine->message_argcount - 1];
866 machine->lookup_class = st_object_class (machine->message_receiver);
867 ip += 1;
868 goto send_common;
871 CASE (SEND_GE) {
873 st_oop a, b;
875 if (ST_LIKELY (st_object_is_smi (sp[-1]) &&
876 st_object_is_smi (sp[-2]))) {
877 b = STACK_POP ();
878 a = STACK_POP ();
879 STACK_PUSH (st_smi_value (a) >= st_smi_value (b) ? ST_TRUE : ST_FALSE);
880 ip++;
881 NEXT ();
884 machine->message_argcount = 1;
885 machine->message_selector = ST_SELECTOR_GE;
886 machine->message_receiver = sp[- machine->message_argcount - 1];
887 machine->lookup_class = st_object_class (machine->message_receiver);
888 ip += 1;
889 goto send_common;
893 CASE (SEND_CLASS) {
895 machine->message_argcount = 0;
896 machine->message_selector = ST_SELECTOR_CLASS;
897 machine->message_receiver = sp[- machine->message_argcount - 1];
898 machine->lookup_class = st_object_class (machine->message_receiver);
899 ip += 1;
900 goto send_common;
903 CASE (SEND_SIZE) {
905 machine->message_argcount = 0;
906 machine->message_selector = ST_SELECTOR_SIZE;
907 machine->message_receiver = sp[- machine->message_argcount - 1];
908 machine->lookup_class = st_object_class (machine->message_receiver);
909 ip += 1;
910 goto send_common;
913 CASE (SEND_AT) {
915 machine->message_argcount = 1;
916 machine->message_selector = ST_SELECTOR_AT;
917 machine->message_receiver = sp[- machine->message_argcount - 1];
918 machine->lookup_class = st_object_class (machine->message_receiver);
919 ip += 1;
920 goto send_common;
923 CASE (SEND_AT_PUT) {
925 machine->message_argcount = 2;
926 machine->message_selector = ST_SELECTOR_ATPUT;
927 machine->message_receiver = sp[- machine->message_argcount - 1];
928 machine->lookup_class = st_object_class (machine->message_receiver);
929 ip += 1;
930 goto send_common;
933 CASE (SEND_EQ) {
935 machine->message_argcount = 1;
936 machine->message_selector = ST_SELECTOR_EQ;
937 machine->message_receiver = sp[- machine->message_argcount - 1];
938 machine->lookup_class = st_object_class (machine->message_receiver);
939 ip += 1;
940 goto send_common;
943 CASE (SEND_NE) {
945 machine->message_argcount = 1;
946 machine->message_selector = ST_SELECTOR_NE;
947 machine->message_receiver = sp[- machine->message_argcount - 1];
948 machine->lookup_class = st_object_class (machine->message_receiver);
949 ip += 1;
950 goto send_common;
953 CASE (SEND_IDENTITY_EQ) {
955 st_oop a, b;
956 a = STACK_POP ();
957 b = STACK_POP ();
959 STACK_PUSH ((a == b) ? ST_TRUE : ST_FALSE);
961 ip += 1;
962 NEXT ();
965 CASE (SEND_VALUE) {
967 machine->message_argcount = 0;
968 machine->message_selector = ST_SELECTOR_VALUE;
969 machine->message_receiver = sp[- machine->message_argcount - 1];
970 machine->lookup_class = st_object_class (machine->message_receiver);
971 ip += 1;
972 goto send_common;
975 CASE (SEND_VALUE_ARG) {
977 machine->message_argcount = 1;
978 machine->message_selector = ST_SELECTOR_VALUE_ARG;
979 machine->message_receiver = sp[- machine->message_argcount - 1];
980 machine->lookup_class = st_object_class (machine->message_receiver);
981 ip += 1;
982 goto send_common;
985 CASE (SEND_NEW) {
987 machine->message_argcount = 0;
988 machine->message_selector = ST_SELECTOR_NEW;
989 machine->message_receiver = sp[- machine->message_argcount - 1];
990 machine->lookup_class = st_object_class (machine->message_receiver);
991 ip += 1;
992 goto send_common;
995 CASE (SEND_NEW_ARG) {
997 machine->message_argcount = 1;
998 machine->message_selector = ST_SELECTOR_NEW_ARG;
999 machine->message_receiver = sp[- machine->message_argcount - 1];
1000 machine->lookup_class = st_object_class (machine->message_receiver);
1001 ip += 1;
1002 goto send_common;
1005 CASE (SEND) {
1007 st_uint primitive_index;
1008 st_method_flags flags;
1009 st_oop context;
1010 st_oop *arguments;
1012 machine->message_argcount = ip[1];
1013 machine->message_selector = st_array_elements (ST_METHOD_LITERALS (machine->method))[ip[2]];
1014 machine->message_receiver = sp[- machine->message_argcount - 1];
1015 machine->lookup_class = st_object_class (machine->message_receiver);
1016 ip += 3;
1018 send_common:
1020 if (!lookup_method_in_cache (machine)) {
1021 STORE_REGISTERS ();
1022 machine->new_method = lookup_method (machine, machine->lookup_class);
1023 LOAD_REGISTERS ();
1024 install_method_in_cache (machine);
1027 flags = st_method_get_flags (machine->new_method);
1028 if (flags == ST_METHOD_PRIMITIVE) {
1029 primitive_index = st_method_get_primitive_index (machine->new_method);
1031 machine->success = true;
1032 STORE_REGISTERS ();
1033 st_primitives[primitive_index].func (machine);
1034 LOAD_REGISTERS ();
1036 if (ST_LIKELY (machine->success))
1037 NEXT ();
1040 /* store registers as a gc could occur */
1041 STORE_REGISTERS ();
1042 context = method_context_new (machine);
1043 LOAD_REGISTERS ();
1044 arguments = ST_METHOD_CONTEXT_STACK (context);
1045 for (int i = 0; i < machine->message_argcount; i++)
1046 arguments[i] = sp[- machine->message_argcount + i];
1047 sp -= machine->message_argcount + 1;
1049 STORE_REGISTERS ();
1050 st_machine_set_active_context (machine, context);
1051 LOAD_REGISTERS ();
1053 /* We have to nil these fields here. Its possible that
1054 that the objects they reference may be zapped by the gc.
1055 Another GC invocation may try to remap these fields not knowing that
1056 the references are invalid.
1057 FIXME: move this nilling out of such a critical execution path */
1058 machine->message_receiver = ST_NIL;
1059 machine->message_selector = ST_NIL;
1061 NEXT ();
1064 CASE (SEND_SUPER) {
1066 st_oop index;
1068 machine->message_argcount = ip[1];
1069 machine->message_selector = st_array_elements (ST_METHOD_LITERALS (machine->method))[ip[2]];
1070 machine->message_receiver = sp[- machine->message_argcount - 1];
1072 index = st_smi_value (st_arrayed_object_size (ST_METHOD_LITERALS (machine->method))) - 1;
1073 machine->lookup_class = ST_BEHAVIOR_SUPERCLASS (st_array_elements (ST_METHOD_LITERALS (machine->method))[index]);
1075 ip += 3;
1077 goto send_common;
1080 CASE (POP_STACK_TOP) {
1082 (void) STACK_POP ();
1084 ip += 1;
1085 NEXT ();
1088 CASE (DUPLICATE_STACK_TOP) {
1090 STACK_PUSH (STACK_PEEK ());
1092 ip += 1;
1093 NEXT ();
1096 CASE (BLOCK_COPY) {
1098 st_oop block;
1099 st_oop home;
1100 st_uint argcount = ip[1];
1101 st_uint initial_ip;
1103 ip += 2;
1105 initial_ip = ip - machine->bytecode + 3;
1107 STORE_REGISTERS ();
1108 block = block_context_new (machine, initial_ip, argcount);
1109 LOAD_REGISTERS ();
1111 STACK_PUSH (block);
1113 NEXT ();
1116 CASE (RETURN_STACK_TOP) {
1118 st_oop sender;
1119 st_oop value;
1120 st_oop home;
1122 value = STACK_PEEK ();
1124 if (ST_OBJECT_CLASS (machine->context) == ST_BLOCK_CONTEXT_CLASS)
1125 sender = ST_CONTEXT_PART_SENDER (ST_BLOCK_CONTEXT_HOME (machine->context));
1126 else {
1127 sender = ST_CONTEXT_PART_SENDER (machine->context);
1128 st_memory_recycle_context (machine->context);
1131 if (ST_UNLIKELY (sender == ST_NIL)) {
1132 STACK_PUSH (machine->context);
1133 STACK_PUSH (value);
1134 SEND_SELECTOR (ST_SELECTOR_CANNOTRETURN, 1);
1135 NEXT ();
1138 st_machine_set_active_context (machine, sender);
1139 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_CONTEXT_PART_SENDER (machine->context);
1152 value = STACK_PEEK ();
1154 st_machine_set_active_context (machine, caller);
1155 LOAD_REGISTERS ();
1156 STACK_PUSH (value);
1158 NEXT ();
1161 INVALID () {
1162 abort ();
1167 out:
1168 st_log ("gc", "totalPauseTime: %.6fs\n",
1169 st_timespec_to_double_seconds (&memory->total_pause_time));
1172 void
1173 st_machine_clear_caches (st_machine *machine)
1175 memset (machine->method_cache, 0, ST_METHOD_CACHE_SIZE * 3 * sizeof (st_oop));
1178 void
1179 st_machine_initialize (st_machine *machine)
1181 st_oop context;
1182 st_oop method;
1184 /* clear contents */
1185 machine->context = ST_NIL;
1186 machine->receiver = ST_NIL;
1187 machine->method = ST_NIL;
1189 machine->sp = 0;
1190 machine->ip = 0;
1191 machine->stack = NULL;
1193 st_machine_clear_caches (machine);
1195 machine->message_argcount = 0;
1196 machine->message_receiver = ST_SMALLTALK;
1197 machine->message_selector = ST_SELECTOR_STARTUPSYSTEM;
1199 machine->new_method = lookup_method (machine, st_object_class (machine->message_receiver));
1200 st_assert (st_method_get_flags (machine->new_method) == ST_METHOD_NORMAL);
1202 context = method_context_new (machine);
1203 st_machine_set_active_context (machine, context);