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
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"
36 #include "st-association.h"
37 #include "st-memory.h"
43 #define HAVE_COMPUTED_GOTO
47 method_context_new (void)
49 register struct st_cpu
*cpu
= &__cpu
;
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
++)
75 block_context_new (st_uint initial_ip
, st_uint argcount
)
77 register struct st_cpu
*cpu
= &__cpu
;
86 context
= st_memory_allocate (ST_SIZE_OOPS (struct st_block_context
) + stack_size
);
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
);
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_HOME (context
) = home
;
113 create_actual_message (void)
115 register struct st_cpu
*cpu
= &__cpu
;
120 array
= st_object_new_arrayed (ST_ARRAY_CLASS
, cpu
->message_argcount
);
121 elements
= st_array_elements (array
);
122 for (st_uint i
= 0; i
< cpu
->message_argcount
; i
++)
123 elements
[i
] = cpu
->stack
[cpu
->sp
- cpu
->message_argcount
+ i
];
125 cpu
->sp
-= cpu
->message_argcount
;
127 message
= st_object_new (ST_MESSAGE_CLASS
);
129 st_memory_perform_gc ();
130 message
= st_object_new (ST_MESSAGE_CLASS
);
131 st_assert (message
!= 0);
134 ST_OBJECT_FIELDS (message
)[0] = cpu
->message_selector
;
135 ST_OBJECT_FIELDS (message
)[1] = array
;
137 ST_STACK_PUSH (cpu
, message
);
139 cpu
->message_selector
= ST_SELECTOR_DOESNOTUNDERSTAND
;
140 cpu
->message_argcount
= 1;
144 lookup_method (st_oop
class)
146 register struct st_cpu
*cpu
= &__cpu
;
147 st_oop method
, dict
, parent
;
151 hash
= st_byte_array_hash (cpu
->message_selector
);
153 while (parent
!= ST_NIL
) {
158 dict
= ST_BEHAVIOR_METHOD_DICTIONARY (parent
);
159 mask
= st_smi_value (st_arrayed_object_size (ST_OBJECT_FIELDS (dict
)[2])) - 1;
160 i
= (hash
& mask
) + 1;
163 el
= st_array_at (ST_OBJECT_FIELDS (dict
)[2], i
);
164 if (el
== ST_NIL
|| el
== (uintptr_t) ST_OBJECT_FIELDS (dict
)[2])
166 if (cpu
->message_selector
== ST_ASSOCIATION_KEY (el
))
167 return ST_ASSOCIATION_VALUE (el
);
168 i
= ((i
+ ST_ADVANCE_SIZE
) & mask
) + 1;
171 parent
= ST_BEHAVIOR_SUPERCLASS (parent
);
174 if (cpu
->message_selector
== ST_SELECTOR_DOESNOTUNDERSTAND
) {
175 fprintf (stderr
, "panda: error: no method found for #doesNotUnderstand:\n");
179 create_actual_message ();
181 return lookup_method (class);
185 st_cpu_lookup_method (st_oop
class)
187 return lookup_method (class);
191 * Creates a new method context. Parameterised by
192 * @sender, @receiver, @method, and @argcount
194 * Message arguments are copied into the new context's temporary
195 * frame. Receiver and arguments are then popped off the stack.
199 activate_method (void)
201 register struct st_cpu
*cpu
= &__cpu
;
205 context
= method_context_new ();
207 arguments
= ST_METHOD_CONTEXT_STACK (context
);
208 for (st_uint i
= 0; i
< cpu
->message_argcount
; i
++)
209 arguments
[i
] = cpu
->stack
[cpu
->sp
- cpu
->message_argcount
+ i
];
211 cpu
->sp
-= cpu
->message_argcount
+ 1;
213 st_cpu_set_active_context (context
);
217 st_cpu_execute_method (void)
219 register struct st_cpu
*cpu
= &__cpu
;
220 st_uint primitive_index
;
221 st_method_flags flags
;
223 flags
= st_method_get_flags (cpu
->new_method
);
224 if (flags
== ST_METHOD_PRIMITIVE
) {
225 primitive_index
= st_method_get_primitive_index (cpu
->new_method
);
227 st_primitives
[primitive_index
].func (cpu
);
228 if (ST_LIKELY (cpu
->success
))
236 st_cpu_set_active_context (st_oop context
)
238 register struct st_cpu
*cpu
= &__cpu
;
241 /* save executation state of active context */
242 if (ST_UNLIKELY (cpu
->context
!= ST_NIL
)) {
243 ST_CONTEXT_PART_IP (cpu
->context
) = st_smi_new (cpu
->ip
);
244 ST_CONTEXT_PART_SP (cpu
->context
) = st_smi_new (cpu
->sp
);
247 if (ST_OBJECT_CLASS (context
) == ST_BLOCK_CONTEXT_CLASS
) {
248 home
= ST_BLOCK_CONTEXT_HOME (context
);
249 cpu
->method
= ST_METHOD_CONTEXT_METHOD (home
);
250 cpu
->receiver
= ST_METHOD_CONTEXT_RECEIVER (home
);
251 cpu
->temps
= ST_METHOD_CONTEXT_STACK (home
);
252 cpu
->stack
= ST_BLOCK_CONTEXT_STACK (context
);
254 cpu
->method
= ST_METHOD_CONTEXT_METHOD (context
);
255 cpu
->receiver
= ST_METHOD_CONTEXT_RECEIVER (context
);
256 cpu
->temps
= ST_METHOD_CONTEXT_STACK (context
);
257 cpu
->stack
= ST_METHOD_CONTEXT_STACK (context
);
260 cpu
->context
= context
;
261 cpu
->sp
= st_smi_value (ST_CONTEXT_PART_SP (context
));
262 cpu
->ip
= st_smi_value (ST_CONTEXT_PART_IP (context
));
263 cpu
->bytecode
= st_method_bytecode_bytes (cpu
->method
);
266 #define SEND_SELECTOR(selector, argcount) \
267 cpu->message_argcount = argcount; \
268 cpu->message_receiver = sp[- argcount - 1]; \
269 cpu->message_selector = selector; \
272 #define SEND_TEMPLATE() \
273 cpu->lookup_class = st_object_class (cpu->message_receiver); \
277 #ifdef HAVE_COMPUTED_GOTO
279 static const st_pointer labels[] = \
283 && PUSH_LITERAL_CONST, \
284 && PUSH_LITERAL_VAR, \
285 && STORE_LITERAL_VAR, \
288 && STORE_POP_LITERAL_VAR, \
290 && STORE_POP_INSTVAR, \
296 && RETURN_STACK_TOP, \
299 && DUPLICATE_STACK_TOP, \
300 && PUSH_ACTIVE_CONTEXT, \
327 && SEND_IDENTITY_EQ, \
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, && INVALID, && INVALID, && INVALID, && INVALID, \
364 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
365 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
366 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
367 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
368 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
369 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
370 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
371 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
381 #ifdef HAVE_COMPUTED_GOTO
382 #define INVALID() INVALID:
385 #define INVALID() default:
386 #define CASE(OP) case OP:
389 #ifdef HAVE_COMPUTED_GOTO
390 #define NEXT() goto *labels[*ip]
392 #define NEXT() goto start
396 install_method_in_cache (void)
398 register struct st_cpu
*cpu
= &__cpu
;
401 index
= ST_METHOD_CACHE_HASH (cpu
->lookup_class
, cpu
->message_selector
) & ST_METHOD_CACHE_MASK
;
402 cpu
->method_cache
[index
].class = cpu
->lookup_class
;
403 cpu
->method_cache
[index
].selector
= cpu
->message_selector
;
404 cpu
->method_cache
[index
].method
= cpu
->new_method
;
408 lookup_method_in_cache (void)
410 register struct st_cpu
*cpu
= &__cpu
;
413 index
= ST_METHOD_CACHE_HASH (cpu
->lookup_class
, cpu
->message_selector
) & ST_METHOD_CACHE_MASK
;
414 if (cpu
->method_cache
[index
].class == cpu
->lookup_class
&&
415 cpu
->method_cache
[index
].selector
== cpu
->message_selector
) {
416 cpu
->new_method
= cpu
->method_cache
[index
].method
;
422 #define STACK_POP(oop) (*--sp)
423 #define STACK_PUSH(oop) (*sp++ = (oop))
424 #define STACK_PEEK(oop) (*(sp-1))
425 #define STACK_UNPOP(count) (sp += count)
426 #define STORE_REGISTERS() \
427 cpu->ip = ip - cpu->bytecode; \
428 cpu->sp = sp - cpu->stack; \
429 ST_CONTEXT_PART_IP (cpu->context) = st_smi_new (cpu->ip);
430 #define LOAD_REGISTERS() \
431 ip = cpu->bytecode + cpu->ip; \
432 sp = cpu->stack + cpu->sp; \
433 ST_CONTEXT_PART_SP (cpu->context) = st_smi_new (cpu->sp);
438 register struct st_cpu
*cpu
= &__cpu
;
439 register const st_uchar
*ip
;
440 register st_oop
*sp
= cpu
->stack
;
442 if (setjmp (cpu
->main_loop
))
445 ip
= cpu
->bytecode
+ cpu
->ip
;
451 STACK_PUSH (cpu
->temps
[ip
[1]]);
457 CASE (PUSH_INSTVAR
) {
459 STACK_PUSH (ST_OBJECT_FIELDS (cpu
->receiver
)[ip
[1]]);
465 CASE (STORE_POP_INSTVAR
) {
467 ST_OBJECT_FIELDS (cpu
->receiver
)[ip
[1]] = STACK_POP ();
473 CASE (STORE_INSTVAR
) {
475 ST_OBJECT_FIELDS (cpu
->receiver
)[ip
[1]] = STACK_PEEK ();
481 CASE (STORE_POP_TEMP
) {
483 cpu
->temps
[ip
[1]] = STACK_POP ();
491 cpu
->temps
[ip
[1]] = STACK_PEEK ();
497 CASE (STORE_LITERAL_VAR
) {
499 ST_ASSOCIATION_VALUE (st_array_elements (ST_METHOD_LITERALS (cpu
->method
))[ip
[1]]) = STACK_PEEK ();
505 CASE (STORE_POP_LITERAL_VAR
) {
507 ST_ASSOCIATION_VALUE (st_array_elements (ST_METHOD_LITERALS (cpu
->method
))[ip
[1]]) = STACK_POP ();
515 STACK_PUSH (cpu
->receiver
);
523 STACK_PUSH (ST_TRUE
);
531 STACK_PUSH (ST_FALSE
);
545 CASE (PUSH_INTEGER
) {
547 STACK_PUSH (st_smi_new ((signed char) ip
[1]));
553 CASE (PUSH_ACTIVE_CONTEXT
) {
555 STACK_PUSH (cpu
->context
);
561 CASE (PUSH_LITERAL_CONST
) {
563 STACK_PUSH (st_array_elements (ST_METHOD_LITERALS (cpu
->method
))[ip
[1]]);
569 CASE (PUSH_LITERAL_VAR
) {
573 var
= ST_ASSOCIATION_VALUE (st_array_elements (ST_METHOD_LITERALS (cpu
->method
))[ip
[1]]);
583 if (STACK_PEEK () == ST_TRUE
) {
585 ip
+= *((unsigned short *) (ip
+ 1)) + 3;
586 } else if (ST_LIKELY (STACK_PEEK () == ST_FALSE
)) {
591 SEND_SELECTOR (ST_SELECTOR_MUSTBEBOOLEAN
, 0);
600 if (STACK_PEEK () == ST_FALSE
) {
602 ip
+= *((unsigned short *) (ip
+ 1)) + 3;
603 } else if (ST_LIKELY (STACK_PEEK () == ST_TRUE
)) {
608 SEND_SELECTOR (ST_SELECTOR_MUSTBEBOOLEAN
, 0);
616 ip
+= *((short *) (ip
+ 1)) + 3;
624 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
625 st_object_is_smi (sp
[-2]))) {
626 b
= st_smi_value (sp
[-1]);
627 a
= st_smi_value (sp
[-2]);
629 if (((result
<< 1) ^ (result
<< 2)) >= 0) {
631 STACK_PUSH (st_smi_new (result
));
637 cpu
->message_argcount
= 1;
638 cpu
->message_selector
= ST_SELECTOR_PLUS
;
639 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
640 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
649 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
650 st_object_is_smi (sp
[-2]))) {
651 b
= st_smi_value (sp
[-1]);
652 a
= st_smi_value (sp
[-2]);
654 if (((result
<< 1) ^ (result
<< 2)) >= 0) {
656 STACK_PUSH (st_smi_new (result
));
664 cpu
->message_argcount
= 1;
665 cpu
->message_selector
= ST_SELECTOR_MINUS
;
666 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
667 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
677 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
678 st_object_is_smi (sp
[-2]))) {
679 b
= st_smi_value (sp
[-1]);
680 a
= st_smi_value (sp
[-2]);
682 if (result
>= ST_SMALL_INTEGER_MIN
&& result
<= ST_SMALL_INTEGER_MAX
) {
684 STACK_PUSH (st_smi_new ((int)result
));
690 cpu
->message_argcount
= 1;
691 cpu
->message_selector
= ST_SELECTOR_MUL
;
692 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
693 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
703 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
704 st_object_is_smi (sp
[-2]))) {
707 STACK_PUSH (st_smi_new (st_smi_value (a
) % st_smi_value (b
)));
712 cpu
->message_argcount
= 1;
713 cpu
->message_selector
= ST_SELECTOR_MOD
;
714 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
715 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
722 cpu
->message_argcount
= 1;
723 cpu
->message_selector
= ST_SELECTOR_DIV
;
724 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
725 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
730 CASE (SEND_BITSHIFT
) {
734 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
735 st_object_is_smi (sp
[-2]))) {
738 if (st_smi_value (b
) < 0) {
739 STACK_PUSH (st_smi_new (st_smi_value (a
) >> -st_smi_value (b
)));
741 STACK_PUSH (st_smi_new (st_smi_value (a
) << st_smi_value (b
)));
746 cpu
->message_argcount
= 1;
747 cpu
->message_selector
= ST_SELECTOR_BITSHIFT
;
748 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
749 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
758 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
759 st_object_is_smi (sp
[-2]))) {
762 STACK_PUSH (st_smi_new (st_smi_value (a
) & st_smi_value (b
)));
767 cpu
->message_argcount
= 1;
768 cpu
->message_selector
= ST_SELECTOR_BITAND
;
769 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
770 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
779 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
780 st_object_is_smi (sp
[-2]))) {
783 STACK_PUSH (st_smi_new (st_smi_value (a
) | st_smi_value (b
)));
788 cpu
->message_argcount
= 1;
789 cpu
->message_selector
= ST_SELECTOR_BITOR
;
790 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
791 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
801 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
802 st_object_is_smi (sp
[-2]))) {
805 STACK_PUSH (st_smi_new (st_smi_value (a
) ^ st_smi_value (b
)));
810 cpu
->message_argcount
= 1;
811 cpu
->message_selector
= ST_SELECTOR_BITXOR
;
812 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
813 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
822 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
823 st_object_is_smi (sp
[-2]))) {
826 STACK_PUSH (st_smi_value (a
) < st_smi_value (b
) ? ST_TRUE
: ST_FALSE
);
831 cpu
->message_argcount
= 1;
832 cpu
->message_selector
= ST_SELECTOR_LT
;
833 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
834 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
843 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
844 st_object_is_smi (sp
[-2]))) {
847 STACK_PUSH (st_smi_value (a
) > st_smi_value (b
) ? ST_TRUE
: ST_FALSE
);
852 cpu
->message_argcount
= 1;
853 cpu
->message_selector
= ST_SELECTOR_GT
;
854 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
855 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
865 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
866 st_object_is_smi (sp
[-2]))) {
869 STACK_PUSH (st_smi_value (a
) <= st_smi_value (b
) ? ST_TRUE
: ST_FALSE
);
874 cpu
->message_argcount
= 1;
875 cpu
->message_selector
= ST_SELECTOR_LE
;
876 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
877 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
886 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
887 st_object_is_smi (sp
[-2]))) {
890 STACK_PUSH (st_smi_value (a
) >= st_smi_value (b
) ? ST_TRUE
: ST_FALSE
);
895 cpu
->message_argcount
= 1;
896 cpu
->message_selector
= ST_SELECTOR_GE
;
897 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
898 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
906 cpu
->message_argcount
= 0;
907 cpu
->message_selector
= ST_SELECTOR_CLASS
;
908 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
909 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
916 cpu
->message_argcount
= 0;
917 cpu
->message_selector
= ST_SELECTOR_SIZE
;
918 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
919 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
926 cpu
->message_argcount
= 1;
927 cpu
->message_selector
= ST_SELECTOR_AT
;
928 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
929 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
936 cpu
->message_argcount
= 2;
937 cpu
->message_selector
= ST_SELECTOR_ATPUT
;
938 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
939 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
946 cpu
->message_argcount
= 1;
947 cpu
->message_selector
= ST_SELECTOR_EQ
;
948 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
949 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
956 cpu
->message_argcount
= 1;
957 cpu
->message_selector
= ST_SELECTOR_NE
;
958 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
959 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
964 CASE (SEND_IDENTITY_EQ
) {
970 STACK_PUSH ((a
== b
) ? ST_TRUE
: ST_FALSE
);
978 cpu
->message_argcount
= 0;
979 cpu
->message_selector
= ST_SELECTOR_VALUE
;
980 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
981 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
986 CASE (SEND_VALUE_ARG
) {
988 cpu
->message_argcount
= 1;
989 cpu
->message_selector
= ST_SELECTOR_VALUE_ARG
;
990 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
991 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
998 cpu
->message_argcount
= 0;
999 cpu
->message_selector
= ST_SELECTOR_NEW
;
1000 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
1001 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
1006 CASE (SEND_NEW_ARG
) {
1008 cpu
->message_argcount
= 1;
1009 cpu
->message_selector
= ST_SELECTOR_NEW_ARG
;
1010 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
1011 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
1018 st_uint primitive_index
;
1019 st_method_flags flags
;
1023 cpu
->message_argcount
= ip
[1];
1024 cpu
->message_selector
= st_array_elements (ST_METHOD_LITERALS (cpu
->method
))[ip
[2]];
1025 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
1026 cpu
->lookup_class
= st_object_class (cpu
->message_receiver
);
1031 if (!lookup_method_in_cache ()) {
1033 cpu
->new_method
= lookup_method (cpu
->lookup_class
);
1035 install_method_in_cache ();
1038 flags
= st_method_get_flags (cpu
->new_method
);
1039 if (flags
== ST_METHOD_PRIMITIVE
) {
1040 primitive_index
= st_method_get_primitive_index (cpu
->new_method
);
1042 cpu
->success
= true;
1044 st_primitives
[primitive_index
].func (cpu
);
1047 if (ST_LIKELY (cpu
->success
))
1051 /* store registers as a gc could occur */
1053 context
= method_context_new ();
1055 arguments
= ST_METHOD_CONTEXT_STACK (context
);
1056 for (int i
= 0; i
< cpu
->message_argcount
; i
++)
1057 arguments
[i
] = sp
[- cpu
->message_argcount
+ i
];
1058 sp
-= cpu
->message_argcount
+ 1;
1061 st_cpu_set_active_context (context
);
1064 /* We have to nil these fields here. Its possible that
1065 that the objects they reference may be zapped by the gc.
1066 Another GC invocation may try to remap these fields not knowing that
1067 the references are invalid.
1068 FIXME: move this nilling out of such a critical execution path */
1069 cpu
->message_receiver
= ST_NIL
;
1070 cpu
->message_selector
= ST_NIL
;
1079 cpu
->message_argcount
= ip
[1];
1080 cpu
->message_selector
= st_array_elements (ST_METHOD_LITERALS (cpu
->method
))[ip
[2]];
1081 cpu
->message_receiver
= sp
[- cpu
->message_argcount
- 1];
1083 index
= st_smi_value (st_arrayed_object_size (ST_METHOD_LITERALS (cpu
->method
))) - 1;
1084 cpu
->lookup_class
= ST_BEHAVIOR_SUPERCLASS (st_array_elements (ST_METHOD_LITERALS (cpu
->method
))[index
]);
1091 CASE (POP_STACK_TOP
) {
1093 (void) STACK_POP ();
1099 CASE (DUPLICATE_STACK_TOP
) {
1101 STACK_PUSH (STACK_PEEK ());
1111 st_uint argcount
= ip
[1];
1116 initial_ip
= ip
- cpu
->bytecode
+ 3;
1119 block
= block_context_new (initial_ip
, argcount
);
1127 CASE (RETURN_STACK_TOP
) {
1133 value
= STACK_PEEK ();
1135 if (ST_OBJECT_CLASS (cpu
->context
) == ST_BLOCK_CONTEXT_CLASS
)
1136 sender
= ST_CONTEXT_PART_SENDER (ST_BLOCK_CONTEXT_HOME (cpu
->context
));
1138 sender
= ST_CONTEXT_PART_SENDER (cpu
->context
);
1139 st_memory_recycle_context (cpu
->context
);
1142 if (ST_UNLIKELY (sender
== ST_NIL
)) {
1143 STACK_PUSH (cpu
->context
);
1145 SEND_SELECTOR (ST_SELECTOR_CANNOTRETURN
, 1);
1149 st_cpu_set_active_context (sender
);
1156 CASE (BLOCK_RETURN
) {
1162 caller
= ST_CONTEXT_PART_SENDER (cpu
->context
);
1163 value
= STACK_PEEK ();
1165 st_cpu_set_active_context (caller
);
1179 st_log ("gc", "totalPauseTime: %.6fs\n",
1180 st_timespec_to_double_seconds (&memory
->total_pause_time
));
1184 st_cpu_clear_caches (void)
1186 memset (__cpu
.method_cache
, 0, ST_METHOD_CACHE_SIZE
* 3 * sizeof (st_oop
));
1190 st_cpu_initialize (void)
1195 /* clear contents */
1196 __cpu
.context
= ST_NIL
;
1197 __cpu
.receiver
= ST_NIL
;
1198 __cpu
.method
= ST_NIL
;
1204 st_cpu_clear_caches ();
1206 __cpu
.message_argcount
= 0;
1207 __cpu
.message_receiver
= ST_SMALLTALK
;
1208 __cpu
.message_selector
= ST_SELECTOR_STARTUPSYSTEM
;
1210 __cpu
.new_method
= lookup_method (st_object_class (__cpu
.message_receiver
));
1211 st_assert (st_method_get_flags (__cpu
.new_method
) == ST_METHOD_NORMAL
);
1213 context
= method_context_new ();
1214 st_cpu_set_active_context (context
);