Remove expensive assertion checks in st-array.h
[panda.git] / src / st-cpu.c
blob783c1151f2f61e93427b61b9332a7c5a617e67f8
1 /*
2 * st-cpu.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 (void)
49 register struct st_cpu *cpu = &__cpu;
50 st_oop context;
51 st_uint temp_count;
52 st_oop *stack;
53 bool large;
55 large = st_method_get_large_context (cpu->new_method);
56 temp_count = st_method_get_arg_count (cpu->new_method) + st_method_get_temp_count (cpu->new_method);
58 context = st_memory_allocate_context (large);
60 ST_CONTEXT_PART_SENDER (context) = cpu->context;
61 ST_CONTEXT_PART_IP (context) = st_smi_new (0);
62 ST_CONTEXT_PART_SP (context) = st_smi_new (temp_count);
63 ST_METHOD_CONTEXT_RECEIVER (context) = cpu->message_receiver;
64 ST_METHOD_CONTEXT_METHOD (context) = cpu->new_method;
66 /* clear temporaries (and nothing above) */
67 stack = ST_METHOD_CONTEXT_STACK (context);
68 for (st_uint i=0; i < temp_count; i++)
69 stack[i] = ST_NIL;
71 return context;
74 static st_oop
75 block_context_new (st_uint initial_ip, st_uint argcount)
77 register struct st_cpu *cpu = &__cpu;
78 st_oop home;
79 st_oop context;
80 st_oop method;
81 st_oop *stack;
82 st_uint stack_size;
84 stack_size = 32;
86 context = st_memory_allocate (ST_SIZE_OOPS (struct st_block_context) + stack_size);
87 if (context == 0) {
88 st_memory_perform_gc ();
89 context = st_memory_allocate (ST_SIZE_OOPS (struct st_block_context) + stack_size);
90 st_assert (context != 0);
93 st_object_initialize_header (context, ST_BLOCK_CONTEXT_CLASS);
94 st_object_set_large_context (context, true);
96 if (ST_OBJECT_CLASS (cpu->context) == ST_BLOCK_CONTEXT_CLASS)
97 home = ST_BLOCK_CONTEXT_HOME (cpu->context);
98 else
99 home = cpu->context;
101 ST_CONTEXT_PART_SENDER (context) = ST_NIL;
102 ST_CONTEXT_PART_IP (context) = st_smi_new (0);
103 ST_CONTEXT_PART_SP (context) = st_smi_new (0);
105 ST_BLOCK_CONTEXT_INITIALIP (context) = st_smi_new (initial_ip);
106 ST_BLOCK_CONTEXT_ARGCOUNT (context) = st_smi_new (argcount);
107 ST_BLOCK_CONTEXT_CALLER (context) = ST_NIL;
108 ST_BLOCK_CONTEXT_HOME (context) = home;
110 /* don't nil stack, not needed */
112 return context;
115 static void
116 create_actual_message (void)
118 register struct st_cpu *cpu = &__cpu;
119 st_oop *elements;
120 st_oop message;
121 st_oop array;
123 array = st_object_new_arrayed (ST_ARRAY_CLASS, cpu->message_argcount);
124 elements = st_array_elements (array);
125 for (st_uint i = 0; i < cpu->message_argcount; i++)
126 elements[i] = cpu->stack[cpu->sp - cpu->message_argcount + i];
128 cpu->sp -= cpu->message_argcount;
130 message = st_object_new (ST_MESSAGE_CLASS);
131 if (message == 0) {
132 st_memory_perform_gc ();
133 message = st_object_new (ST_MESSAGE_CLASS);
134 st_assert (message != 0);
137 ST_OBJECT_FIELDS (message)[0] = cpu->message_selector;
138 ST_OBJECT_FIELDS (message)[1] = array;
140 ST_STACK_PUSH (cpu, message);
142 cpu->message_selector = ST_SELECTOR_DOESNOTUNDERSTAND;
143 cpu->message_argcount = 1;
146 static st_oop
147 lookup_method (st_oop class)
149 register struct st_cpu *cpu = &__cpu;
150 st_oop method;
151 st_oop parent = class;
152 st_uint index;
154 while (parent != ST_NIL) {
155 method = st_dictionary_at (ST_BEHAVIOR_METHOD_DICTIONARY (parent), cpu->message_selector);
156 if (method != ST_NIL)
157 return method;
158 parent = ST_BEHAVIOR_SUPERCLASS (parent);
161 if (cpu->message_selector == ST_SELECTOR_DOESNOTUNDERSTAND) {
162 fprintf (stderr, "panda: error: no method found for #doesNotUnderstand:\n");
163 exit(1);
166 create_actual_message ();
168 return lookup_method (class);
171 st_oop
172 st_cpu_lookup_method (st_oop class)
174 return lookup_method (class);
178 * Creates a new method context. Parameterised by
179 * @sender, @receiver, @method, and @argcount
181 * Message arguments are copied into the new context's temporary
182 * frame. Receiver and arguments are then popped off the stack.
185 static inline void
186 activate_method (void)
188 register struct st_cpu *cpu = &__cpu;
189 st_oop context;
190 st_oop *arguments;
192 context = method_context_new ();
194 arguments = ST_METHOD_CONTEXT_STACK (context);
195 for (st_uint i = 0; i < cpu->message_argcount; i++)
196 arguments[i] = cpu->stack[cpu->sp - cpu->message_argcount + i];
198 cpu->sp -= cpu->message_argcount + 1;
200 st_cpu_set_active_context (context);
203 void
204 st_cpu_execute_method (void)
206 register struct st_cpu *cpu = &__cpu;
207 st_uint primitive_index;
208 st_method_flags flags;
210 flags = st_method_get_flags (cpu->new_method);
211 if (flags == ST_METHOD_PRIMITIVE) {
212 primitive_index = st_method_get_primitive_index (cpu->new_method);
213 cpu->success = true;
214 st_primitives[primitive_index].func (cpu);
215 if (ST_LIKELY (cpu->success))
216 return;
219 activate_method ();
222 void
223 st_cpu_set_active_context (st_oop context)
225 register struct st_cpu *cpu = &__cpu;
226 st_oop home;
228 /* save executation state of active context */
229 if (ST_UNLIKELY (cpu->context != ST_NIL)) {
230 ST_CONTEXT_PART_IP (cpu->context) = st_smi_new (cpu->ip);
231 ST_CONTEXT_PART_SP (cpu->context) = st_smi_new (cpu->sp);
234 if (ST_OBJECT_CLASS (context) == ST_BLOCK_CONTEXT_CLASS) {
235 home = ST_BLOCK_CONTEXT_HOME (context);
236 cpu->method = ST_METHOD_CONTEXT_METHOD (home);
237 cpu->receiver = ST_METHOD_CONTEXT_RECEIVER (home);
238 cpu->literals = st_array_elements (ST_METHOD_LITERALS (cpu->method));
239 cpu->temps = ST_METHOD_CONTEXT_STACK (home);
240 cpu->stack = ST_BLOCK_CONTEXT_STACK (context);
241 } else {
242 cpu->method = ST_METHOD_CONTEXT_METHOD (context);
243 cpu->receiver = ST_METHOD_CONTEXT_RECEIVER (context);
244 cpu->literals = st_array_elements (ST_METHOD_LITERALS (cpu->method));
245 cpu->temps = ST_METHOD_CONTEXT_STACK (context);
246 cpu->stack = ST_METHOD_CONTEXT_STACK (context);
249 cpu->context = context;
250 cpu->sp = st_smi_value (ST_CONTEXT_PART_SP (context));
251 cpu->ip = st_smi_value (ST_CONTEXT_PART_IP (context));
252 cpu->bytecode = st_method_bytecode_bytes (cpu->method);
255 #define SEND_SELECTOR(selector, argcount) \
256 cpu->message_argcount = argcount; \
257 cpu->message_receiver = sp[- argcount - 1]; \
258 cpu->message_selector = selector; \
259 goto send_common;
261 #define SEND_TEMPLATE() \
262 cpu->lookup_class = st_object_class (cpu->message_receiver); \
263 ip += 1; \
264 goto common;
266 #ifdef HAVE_COMPUTED_GOTO
267 #define SWITCH(ip) \
268 static const st_pointer labels[] = \
270 && PUSH_TEMP, \
271 && PUSH_INSTVAR, \
272 && PUSH_LITERAL_CONST, \
273 && PUSH_LITERAL_VAR, \
274 && STORE_LITERAL_VAR, \
275 && STORE_TEMP, \
276 && STORE_INSTVAR, \
277 && STORE_POP_LITERAL_VAR, \
278 && STORE_POP_TEMP, \
279 && STORE_POP_INSTVAR, \
280 && PUSH_SELF, \
281 && PUSH_NIL, \
282 && PUSH_TRUE, \
283 && PUSH_FALSE, \
284 && PUSH_INTEGER, \
285 && RETURN_STACK_TOP, \
286 && BLOCK_RETURN, \
287 && POP_STACK_TOP, \
288 && DUPLICATE_STACK_TOP, \
289 && PUSH_ACTIVE_CONTEXT, \
290 && BLOCK_COPY, \
291 && JUMP_TRUE, \
292 && JUMP_FALSE, \
293 && JUMP, \
294 && SEND, \
295 && SEND_SUPER, \
296 && SEND_PLUS, \
297 && SEND_MINUS, \
298 && SEND_LT, \
299 && SEND_GT, \
300 && SEND_LE, \
301 && SEND_GE, \
302 && SEND_EQ, \
303 && SEND_NE, \
304 && SEND_MUL, \
305 && SEND_DIV, \
306 && SEND_MOD, \
307 && SEND_BITSHIFT, \
308 && SEND_BITAND, \
309 && SEND_BITOR, \
310 && SEND_BITXOR, \
311 && SEND_AT, \
312 && SEND_AT_PUT, \
313 && SEND_SIZE, \
314 && SEND_VALUE, \
315 && SEND_VALUE_ARG, \
316 && SEND_IDENTITY_EQ, \
317 && SEND_CLASS, \
318 && SEND_NEW, \
319 && SEND_NEW_ARG, \
320 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
321 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
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, \
362 }; \
363 goto *labels[*ip];
364 #else
365 #define SWITCH(ip) \
366 start: \
367 switch (*ip)
368 #endif
370 #ifdef HAVE_COMPUTED_GOTO
371 #define INVALID() INVALID:
372 #define CASE(OP) OP:
373 #else
374 #define INVALID() default:
375 #define CASE(OP) case OP:
376 #endif
378 #ifdef HAVE_COMPUTED_GOTO
379 #define NEXT() goto *labels[*ip]
380 #else
381 #define NEXT() goto start
382 #endif
384 static inline void
385 install_method_in_cache (void)
387 register struct st_cpu *cpu = &__cpu;
388 st_uint index;
390 index = ST_METHOD_CACHE_HASH (cpu->lookup_class, cpu->message_selector) & ST_METHOD_CACHE_MASK;
391 cpu->method_cache[index].class = cpu->lookup_class;
392 cpu->method_cache[index].selector = cpu->message_selector;
393 cpu->method_cache[index].method = cpu->new_method;
396 static inline bool
397 lookup_method_in_cache (void)
399 register struct st_cpu *cpu = &__cpu;
400 st_uint index;
402 index = ST_METHOD_CACHE_HASH (cpu->lookup_class, cpu->message_selector) & ST_METHOD_CACHE_MASK;
403 if (cpu->method_cache[index].class == cpu->lookup_class &&
404 cpu->method_cache[index].selector == cpu->message_selector) {
405 cpu->new_method = cpu->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 cpu->ip = ip - cpu->bytecode; \
417 cpu->sp = sp - cpu->stack; \
418 ST_CONTEXT_PART_IP (cpu->context) = st_smi_new (cpu->ip);
419 #define LOAD_REGISTERS() \
420 ip = cpu->bytecode + cpu->ip; \
421 sp = cpu->stack + cpu->sp; \
422 ST_CONTEXT_PART_SP (cpu->context) = st_smi_new (cpu->sp);
424 void
425 st_cpu_main (void)
427 register struct st_cpu *cpu = &__cpu;
428 register const st_uchar *ip;
429 register st_oop *sp = cpu->stack;
431 if (setjmp (cpu->main_loop))
432 goto out;
434 ip = cpu->bytecode + cpu->ip;
436 SWITCH (ip) {
438 CASE (PUSH_TEMP) {
440 STACK_PUSH (cpu->temps[ip[1]]);
442 ip += 2;
443 NEXT ();
446 CASE (PUSH_INSTVAR) {
448 STACK_PUSH (ST_OBJECT_FIELDS (cpu->receiver)[ip[1]]);
450 ip += 2;
451 NEXT ();
454 CASE (STORE_POP_INSTVAR) {
456 ST_OBJECT_FIELDS (cpu->receiver)[ip[1]] = STACK_POP ();
458 ip += 2;
459 NEXT ();
462 CASE (STORE_INSTVAR) {
464 ST_OBJECT_FIELDS (cpu->receiver)[ip[1]] = STACK_PEEK ();
466 ip += 2;
467 NEXT ();
470 CASE (STORE_POP_TEMP) {
472 cpu->temps[ip[1]] = STACK_POP ();
474 ip += 2;
475 NEXT ();
478 CASE (STORE_TEMP) {
480 cpu->temps[ip[1]] = STACK_PEEK ();
482 ip += 2;
483 NEXT ();
486 CASE (STORE_LITERAL_VAR) {
488 ST_ASSOCIATION_VALUE (cpu->literals[ip[1]]) = STACK_PEEK ();
490 ip += 2;
491 NEXT ();
494 CASE (STORE_POP_LITERAL_VAR) {
496 ST_ASSOCIATION_VALUE (cpu->literals[ip[1]]) = STACK_POP ();
498 ip += 2;
499 NEXT ();
502 CASE (PUSH_SELF) {
504 STACK_PUSH (cpu->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 (cpu->context);
546 ip += 1;
547 NEXT ();
550 CASE (PUSH_LITERAL_CONST) {
552 STACK_PUSH (cpu->literals[ip[1]]);
554 ip += 2;
555 NEXT ();
558 CASE (PUSH_LITERAL_VAR) {
560 st_oop var;
562 var = ST_ASSOCIATION_VALUE (cpu->literals[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 cpu->message_argcount = 1;
627 cpu->message_selector = ST_SELECTOR_PLUS;
628 cpu->message_receiver = sp[- cpu->message_argcount - 1];
629 cpu->lookup_class = st_object_class (cpu->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 cpu->message_argcount = 1;
654 cpu->message_selector = ST_SELECTOR_MINUS;
655 cpu->message_receiver = sp[- cpu->message_argcount - 1];
656 cpu->lookup_class = st_object_class (cpu->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 cpu->message_argcount = 1;
680 cpu->message_selector = ST_SELECTOR_MUL;
681 cpu->message_receiver = sp[- cpu->message_argcount - 1];
682 cpu->lookup_class = st_object_class (cpu->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 cpu->message_argcount = 1;
702 cpu->message_selector = ST_SELECTOR_MOD;
703 cpu->message_receiver = sp[- cpu->message_argcount - 1];
704 cpu->lookup_class = st_object_class (cpu->message_receiver);
705 ip += 1;
706 goto send_common;
709 CASE (SEND_DIV) {
711 cpu->message_argcount = 1;
712 cpu->message_selector = ST_SELECTOR_DIV;
713 cpu->message_receiver = sp[- cpu->message_argcount - 1];
714 cpu->lookup_class = st_object_class (cpu->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 cpu->message_argcount = 1;
736 cpu->message_selector = ST_SELECTOR_BITSHIFT;
737 cpu->message_receiver = sp[- cpu->message_argcount - 1];
738 cpu->lookup_class = st_object_class (cpu->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 cpu->message_argcount = 1;
757 cpu->message_selector = ST_SELECTOR_BITAND;
758 cpu->message_receiver = sp[- cpu->message_argcount - 1];
759 cpu->lookup_class = st_object_class (cpu->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 cpu->message_argcount = 1;
778 cpu->message_selector = ST_SELECTOR_BITOR;
779 cpu->message_receiver = sp[- cpu->message_argcount - 1];
780 cpu->lookup_class = st_object_class (cpu->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 cpu->message_argcount = 1;
800 cpu->message_selector = ST_SELECTOR_BITXOR;
801 cpu->message_receiver = sp[- cpu->message_argcount - 1];
802 cpu->lookup_class = st_object_class (cpu->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 cpu->message_argcount = 1;
821 cpu->message_selector = ST_SELECTOR_LT;
822 cpu->message_receiver = sp[- cpu->message_argcount - 1];
823 cpu->lookup_class = st_object_class (cpu->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 cpu->message_argcount = 1;
842 cpu->message_selector = ST_SELECTOR_GT;
843 cpu->message_receiver = sp[- cpu->message_argcount - 1];
844 cpu->lookup_class = st_object_class (cpu->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 cpu->message_argcount = 1;
864 cpu->message_selector = ST_SELECTOR_LE;
865 cpu->message_receiver = sp[- cpu->message_argcount - 1];
866 cpu->lookup_class = st_object_class (cpu->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 cpu->message_argcount = 1;
885 cpu->message_selector = ST_SELECTOR_GE;
886 cpu->message_receiver = sp[- cpu->message_argcount - 1];
887 cpu->lookup_class = st_object_class (cpu->message_receiver);
888 ip += 1;
889 goto send_common;
893 CASE (SEND_CLASS) {
895 cpu->message_argcount = 0;
896 cpu->message_selector = ST_SELECTOR_CLASS;
897 cpu->message_receiver = sp[- cpu->message_argcount - 1];
898 cpu->lookup_class = st_object_class (cpu->message_receiver);
899 ip += 1;
900 goto send_common;
903 CASE (SEND_SIZE) {
905 cpu->message_argcount = 0;
906 cpu->message_selector = ST_SELECTOR_SIZE;
907 cpu->message_receiver = sp[- cpu->message_argcount - 1];
908 cpu->lookup_class = st_object_class (cpu->message_receiver);
909 ip += 1;
910 goto send_common;
913 CASE (SEND_AT) {
915 cpu->message_argcount = 1;
916 cpu->message_selector = ST_SELECTOR_AT;
917 cpu->message_receiver = sp[- cpu->message_argcount - 1];
918 cpu->lookup_class = st_object_class (cpu->message_receiver);
919 ip += 1;
920 goto send_common;
923 CASE (SEND_AT_PUT) {
925 cpu->message_argcount = 2;
926 cpu->message_selector = ST_SELECTOR_ATPUT;
927 cpu->message_receiver = sp[- cpu->message_argcount - 1];
928 cpu->lookup_class = st_object_class (cpu->message_receiver);
929 ip += 1;
930 goto send_common;
933 CASE (SEND_EQ) {
935 cpu->message_argcount = 1;
936 cpu->message_selector = ST_SELECTOR_EQ;
937 cpu->message_receiver = sp[- cpu->message_argcount - 1];
938 cpu->lookup_class = st_object_class (cpu->message_receiver);
939 ip += 1;
940 goto send_common;
943 CASE (SEND_NE) {
945 cpu->message_argcount = 1;
946 cpu->message_selector = ST_SELECTOR_NE;
947 cpu->message_receiver = sp[- cpu->message_argcount - 1];
948 cpu->lookup_class = st_object_class (cpu->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 cpu->message_argcount = 0;
968 cpu->message_selector = ST_SELECTOR_VALUE;
969 cpu->message_receiver = sp[- cpu->message_argcount - 1];
970 cpu->lookup_class = st_object_class (cpu->message_receiver);
971 ip += 1;
972 goto send_common;
975 CASE (SEND_VALUE_ARG) {
977 cpu->message_argcount = 1;
978 cpu->message_selector = ST_SELECTOR_VALUE_ARG;
979 cpu->message_receiver = sp[- cpu->message_argcount - 1];
980 cpu->lookup_class = st_object_class (cpu->message_receiver);
981 ip += 1;
982 goto send_common;
985 CASE (SEND_NEW) {
987 cpu->message_argcount = 0;
988 cpu->message_selector = ST_SELECTOR_NEW;
989 cpu->message_receiver = sp[- cpu->message_argcount - 1];
990 cpu->lookup_class = st_object_class (cpu->message_receiver);
991 ip += 1;
992 goto send_common;
995 CASE (SEND_NEW_ARG) {
997 cpu->message_argcount = 1;
998 cpu->message_selector = ST_SELECTOR_NEW_ARG;
999 cpu->message_receiver = sp[- cpu->message_argcount - 1];
1000 cpu->lookup_class = st_object_class (cpu->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 cpu->message_argcount = ip[1];
1013 cpu->message_selector = cpu->literals[ip[2]];
1014 cpu->message_receiver = sp[- cpu->message_argcount - 1];
1015 cpu->lookup_class = st_object_class (cpu->message_receiver);
1016 ip += 3;
1018 send_common:
1020 if (!lookup_method_in_cache ()) {
1021 STORE_REGISTERS ();
1022 cpu->new_method = lookup_method (cpu->lookup_class);
1023 LOAD_REGISTERS ();
1024 install_method_in_cache ();
1027 flags = st_method_get_flags (cpu->new_method);
1028 if (flags == ST_METHOD_PRIMITIVE) {
1029 primitive_index = st_method_get_primitive_index (cpu->new_method);
1031 cpu->success = true;
1032 STORE_REGISTERS ();
1033 st_primitives[primitive_index].func (cpu);
1034 LOAD_REGISTERS ();
1036 if (ST_LIKELY (cpu->success))
1037 NEXT ();
1040 /* store registers as a gc could occur */
1041 STORE_REGISTERS ();
1042 context = method_context_new ();
1043 LOAD_REGISTERS ();
1044 arguments = ST_METHOD_CONTEXT_STACK (context);
1045 for (int i = 0; i < cpu->message_argcount; i++)
1046 arguments[i] = sp[- cpu->message_argcount + i];
1047 sp -= cpu->message_argcount + 1;
1049 STORE_REGISTERS ();
1050 st_cpu_set_active_context (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 cpu->message_receiver = ST_NIL;
1059 cpu->message_selector = ST_NIL;
1061 NEXT ();
1064 CASE (SEND_SUPER) {
1066 st_oop index;
1068 cpu->message_argcount = ip[1];
1069 cpu->message_selector = cpu->literals[ip[2]];
1070 cpu->message_receiver = sp[- cpu->message_argcount - 1];
1072 index = st_smi_value (st_arrayed_object_size (ST_METHOD_LITERALS (cpu->method))) - 1;
1073 cpu->lookup_class = ST_BEHAVIOR_SUPERCLASS (cpu->literals[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 - cpu->bytecode + 3;
1107 STORE_REGISTERS ();
1108 block = block_context_new (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 (cpu->context) == ST_BLOCK_CONTEXT_CLASS)
1125 sender = ST_CONTEXT_PART_SENDER (ST_BLOCK_CONTEXT_HOME (cpu->context));
1126 else {
1127 sender = ST_CONTEXT_PART_SENDER (cpu->context);
1128 st_memory_recycle_context (cpu->context);
1131 if (ST_UNLIKELY (sender == ST_NIL)) {
1132 STACK_PUSH (cpu->context);
1133 STACK_PUSH (value);
1134 SEND_SELECTOR (ST_SELECTOR_CANNOTRETURN, 1);
1135 NEXT ();
1138 st_cpu_set_active_context (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_BLOCK_CONTEXT_CALLER (cpu->context);
1152 value = STACK_PEEK ();
1154 st_cpu_set_active_context (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_cpu_clear_caches (void)
1175 memset (__cpu.method_cache, 0, ST_METHOD_CACHE_SIZE * 3 * sizeof (st_oop));
1178 void
1179 st_cpu_initialize (void)
1181 st_oop context;
1182 st_oop method;
1184 /* clear contents */
1185 __cpu.context = ST_NIL;
1186 __cpu.receiver = ST_NIL;
1187 __cpu.method = ST_NIL;
1189 __cpu.sp = 0;
1190 __cpu.ip = 0;
1191 __cpu.stack = NULL;
1193 st_cpu_clear_caches ();
1195 __cpu.message_argcount = 0;
1196 __cpu.message_receiver = ST_SMALLTALK;
1197 __cpu.message_selector = ST_SELECTOR_STARTUPSYSTEM;
1199 __cpu.new_method = lookup_method (st_object_class (__cpu.message_receiver));
1200 st_assert (st_method_get_flags (__cpu.new_method) == ST_METHOD_NORMAL);
1202 context = method_context_new ();
1203 st_cpu_set_active_context (context);