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_CALLER (context
) = ST_NIL
;
108 ST_BLOCK_CONTEXT_HOME (context
) = home
;
110 /* don't nil stack, not needed */
116 create_actual_message (void)
118 register struct st_cpu
*cpu
= &__cpu
;
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
);
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;
147 lookup_method (st_oop
class)
149 register struct st_cpu
*cpu
= &__cpu
;
151 st_oop parent
= class;
154 while (parent
!= ST_NIL
) {
155 method
= st_dictionary_at (ST_BEHAVIOR_METHOD_DICTIONARY (parent
), cpu
->message_selector
);
156 if (method
!= ST_NIL
)
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");
166 create_actual_message ();
168 return lookup_method (class);
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.
186 activate_method (void)
188 register struct st_cpu
*cpu
= &__cpu
;
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
);
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
);
214 st_primitives
[primitive_index
].func (cpu
);
215 if (ST_LIKELY (cpu
->success
))
223 st_cpu_set_active_context (st_oop context
)
225 register struct st_cpu
*cpu
= &__cpu
;
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
);
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; \
261 #define SEND_TEMPLATE() \
262 cpu->lookup_class = st_object_class (cpu->message_receiver); \
266 #ifdef HAVE_COMPUTED_GOTO
268 static const st_pointer labels[] = \
272 && PUSH_LITERAL_CONST, \
273 && PUSH_LITERAL_VAR, \
274 && STORE_LITERAL_VAR, \
277 && STORE_POP_LITERAL_VAR, \
279 && STORE_POP_INSTVAR, \
285 && RETURN_STACK_TOP, \
288 && DUPLICATE_STACK_TOP, \
289 && PUSH_ACTIVE_CONTEXT, \
316 && SEND_IDENTITY_EQ, \
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, \
370 #ifdef HAVE_COMPUTED_GOTO
371 #define INVALID() INVALID:
374 #define INVALID() default:
375 #define CASE(OP) case OP:
378 #ifdef HAVE_COMPUTED_GOTO
379 #define NEXT() goto *labels[*ip]
381 #define NEXT() goto start
385 install_method_in_cache (void)
387 register struct st_cpu
*cpu
= &__cpu
;
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
;
397 lookup_method_in_cache (void)
399 register struct st_cpu
*cpu
= &__cpu
;
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
;
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);
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
))
434 ip
= cpu
->bytecode
+ cpu
->ip
;
440 STACK_PUSH (cpu
->temps
[ip
[1]]);
446 CASE (PUSH_INSTVAR
) {
448 STACK_PUSH (ST_OBJECT_FIELDS (cpu
->receiver
)[ip
[1]]);
454 CASE (STORE_POP_INSTVAR
) {
456 ST_OBJECT_FIELDS (cpu
->receiver
)[ip
[1]] = STACK_POP ();
462 CASE (STORE_INSTVAR
) {
464 ST_OBJECT_FIELDS (cpu
->receiver
)[ip
[1]] = STACK_PEEK ();
470 CASE (STORE_POP_TEMP
) {
472 cpu
->temps
[ip
[1]] = STACK_POP ();
480 cpu
->temps
[ip
[1]] = STACK_PEEK ();
486 CASE (STORE_LITERAL_VAR
) {
488 ST_ASSOCIATION_VALUE (cpu
->literals
[ip
[1]]) = STACK_PEEK ();
494 CASE (STORE_POP_LITERAL_VAR
) {
496 ST_ASSOCIATION_VALUE (cpu
->literals
[ip
[1]]) = STACK_POP ();
504 STACK_PUSH (cpu
->receiver
);
512 STACK_PUSH (ST_TRUE
);
520 STACK_PUSH (ST_FALSE
);
534 CASE (PUSH_INTEGER
) {
536 STACK_PUSH (st_smi_new ((signed char) ip
[1]));
542 CASE (PUSH_ACTIVE_CONTEXT
) {
544 STACK_PUSH (cpu
->context
);
550 CASE (PUSH_LITERAL_CONST
) {
552 STACK_PUSH (cpu
->literals
[ip
[1]]);
558 CASE (PUSH_LITERAL_VAR
) {
562 var
= ST_ASSOCIATION_VALUE (cpu
->literals
[ip
[1]]);
572 if (STACK_PEEK () == ST_TRUE
) {
574 ip
+= *((unsigned short *) (ip
+ 1)) + 3;
575 } else if (ST_LIKELY (STACK_PEEK () == ST_FALSE
)) {
580 SEND_SELECTOR (ST_SELECTOR_MUSTBEBOOLEAN
, 0);
589 if (STACK_PEEK () == ST_FALSE
) {
591 ip
+= *((unsigned short *) (ip
+ 1)) + 3;
592 } else if (ST_LIKELY (STACK_PEEK () == ST_TRUE
)) {
597 SEND_SELECTOR (ST_SELECTOR_MUSTBEBOOLEAN
, 0);
605 ip
+= *((short *) (ip
+ 1)) + 3;
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]);
618 if (((result
<< 1) ^ (result
<< 2)) >= 0) {
620 STACK_PUSH (st_smi_new (result
));
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
);
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]);
643 if (((result
<< 1) ^ (result
<< 2)) >= 0) {
645 STACK_PUSH (st_smi_new (result
));
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
);
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]);
671 if (result
>= ST_SMALL_INTEGER_MIN
&& result
<= ST_SMALL_INTEGER_MAX
) {
673 STACK_PUSH (st_smi_new ((int)result
));
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
);
692 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
693 st_object_is_smi (sp
[-2]))) {
696 STACK_PUSH (st_smi_new (st_smi_value (a
) % st_smi_value (b
)));
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
);
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
);
719 CASE (SEND_BITSHIFT
) {
723 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
724 st_object_is_smi (sp
[-2]))) {
727 if (st_smi_value (b
) < 0) {
728 STACK_PUSH (st_smi_new (st_smi_value (a
) >> -st_smi_value (b
)));
730 STACK_PUSH (st_smi_new (st_smi_value (a
) << st_smi_value (b
)));
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
);
747 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
748 st_object_is_smi (sp
[-2]))) {
751 STACK_PUSH (st_smi_new (st_smi_value (a
) & st_smi_value (b
)));
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
);
768 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
769 st_object_is_smi (sp
[-2]))) {
772 STACK_PUSH (st_smi_new (st_smi_value (a
) | st_smi_value (b
)));
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
);
790 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
791 st_object_is_smi (sp
[-2]))) {
794 STACK_PUSH (st_smi_new (st_smi_value (a
) ^ st_smi_value (b
)));
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
);
811 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
812 st_object_is_smi (sp
[-2]))) {
815 STACK_PUSH (st_smi_value (a
) < st_smi_value (b
) ? ST_TRUE
: ST_FALSE
);
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
);
832 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
833 st_object_is_smi (sp
[-2]))) {
836 STACK_PUSH (st_smi_value (a
) > st_smi_value (b
) ? ST_TRUE
: ST_FALSE
);
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
);
854 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
855 st_object_is_smi (sp
[-2]))) {
858 STACK_PUSH (st_smi_value (a
) <= st_smi_value (b
) ? ST_TRUE
: ST_FALSE
);
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
);
875 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
876 st_object_is_smi (sp
[-2]))) {
879 STACK_PUSH (st_smi_value (a
) >= st_smi_value (b
) ? ST_TRUE
: ST_FALSE
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
953 CASE (SEND_IDENTITY_EQ
) {
959 STACK_PUSH ((a
== b
) ? ST_TRUE
: ST_FALSE
);
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
);
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
);
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
);
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
);
1007 st_uint primitive_index
;
1008 st_method_flags flags
;
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
);
1020 if (!lookup_method_in_cache ()) {
1022 cpu
->new_method
= lookup_method (cpu
->lookup_class
);
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;
1033 st_primitives
[primitive_index
].func (cpu
);
1036 if (ST_LIKELY (cpu
->success
))
1040 /* store registers as a gc could occur */
1042 context
= method_context_new ();
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;
1050 st_cpu_set_active_context (context
);
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
;
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
]);
1080 CASE (POP_STACK_TOP
) {
1082 (void) STACK_POP ();
1088 CASE (DUPLICATE_STACK_TOP
) {
1090 STACK_PUSH (STACK_PEEK ());
1100 st_uint argcount
= ip
[1];
1105 initial_ip
= ip
- cpu
->bytecode
+ 3;
1108 block
= block_context_new (initial_ip
, argcount
);
1116 CASE (RETURN_STACK_TOP
) {
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
));
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
);
1134 SEND_SELECTOR (ST_SELECTOR_CANNOTRETURN
, 1);
1138 st_cpu_set_active_context (sender
);
1145 CASE (BLOCK_RETURN
) {
1151 caller
= ST_BLOCK_CONTEXT_CALLER (cpu
->context
);
1152 value
= STACK_PEEK ();
1154 st_cpu_set_active_context (caller
);
1168 st_log ("gc", "totalPauseTime: %.6fs\n",
1169 st_timespec_to_double_seconds (&memory
->total_pause_time
));
1173 st_cpu_clear_caches (void)
1175 memset (__cpu
.method_cache
, 0, ST_METHOD_CACHE_SIZE
* 3 * sizeof (st_oop
));
1179 st_cpu_initialize (void)
1184 /* clear contents */
1185 __cpu
.context
= ST_NIL
;
1186 __cpu
.receiver
= ST_NIL
;
1187 __cpu
.method
= ST_NIL
;
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
);