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 (st_machine
*machine
)
54 large
= st_method_get_large_context (machine
->new_method
);
55 temp_count
= st_method_get_arg_count (machine
->new_method
) + st_method_get_temp_count (machine
->new_method
);
57 context
= st_memory_allocate_context (large
);
59 ST_CONTEXT_PART_SENDER (context
) = machine
->context
;
60 ST_CONTEXT_PART_IP (context
) = st_smi_new (0);
61 ST_CONTEXT_PART_SP (context
) = st_smi_new (temp_count
);
62 ST_METHOD_CONTEXT_RECEIVER (context
) = machine
->message_receiver
;
63 ST_METHOD_CONTEXT_METHOD (context
) = machine
->new_method
;
65 /* clear temporaries (and nothing above) */
66 stack
= ST_METHOD_CONTEXT_STACK (context
);
67 for (st_uint i
=0; i
< temp_count
; i
++)
74 block_context_new (st_machine
*machine
, st_uint initial_ip
, st_uint argcount
)
84 context
= st_memory_allocate (ST_SIZE_OOPS (struct st_block_context
) + stack_size
);
86 st_memory_perform_gc ();
87 context
= st_memory_allocate (ST_SIZE_OOPS (struct st_block_context
) + stack_size
);
88 st_assert (context
!= 0);
91 st_object_initialize_header (context
, ST_BLOCK_CONTEXT_CLASS
);
92 st_object_set_large_context (context
, true);
94 if (ST_OBJECT_CLASS (machine
->context
) == ST_BLOCK_CONTEXT_CLASS
)
95 home
= ST_BLOCK_CONTEXT_HOME (machine
->context
);
97 home
= machine
->context
;
99 ST_CONTEXT_PART_SENDER (context
) = ST_NIL
;
100 ST_CONTEXT_PART_IP (context
) = st_smi_new (0);
101 ST_CONTEXT_PART_SP (context
) = st_smi_new (0);
103 ST_BLOCK_CONTEXT_INITIALIP (context
) = st_smi_new (initial_ip
);
104 ST_BLOCK_CONTEXT_ARGCOUNT (context
) = st_smi_new (argcount
);
105 ST_BLOCK_CONTEXT_HOME (context
) = home
;
111 create_actual_message (st_machine
*machine
)
117 array
= st_object_new_arrayed (ST_ARRAY_CLASS
, machine
->message_argcount
);
118 elements
= st_array_elements (array
);
119 for (st_uint i
= 0; i
< machine
->message_argcount
; i
++)
120 elements
[i
] = machine
->stack
[machine
->sp
- machine
->message_argcount
+ i
];
122 machine
->sp
-= machine
->message_argcount
;
124 message
= st_object_new (ST_MESSAGE_CLASS
);
126 st_memory_perform_gc ();
127 message
= st_object_new (ST_MESSAGE_CLASS
);
128 st_assert (message
!= 0);
131 ST_OBJECT_FIELDS (message
)[0] = machine
->message_selector
;
132 ST_OBJECT_FIELDS (message
)[1] = array
;
134 ST_STACK_PUSH (machine
, message
);
136 machine
->message_selector
= ST_SELECTOR_DOESNOTUNDERSTAND
;
137 machine
->message_argcount
= 1;
141 lookup_method (st_machine
*machine
, st_oop
class)
143 st_oop method
, dict
, parent
;
147 hash
= st_byte_array_hash (machine
->message_selector
);
149 while (parent
!= ST_NIL
) {
154 dict
= ST_BEHAVIOR_METHOD_DICTIONARY (parent
);
155 mask
= st_smi_value (st_arrayed_object_size (ST_OBJECT_FIELDS (dict
)[2])) - 1;
156 i
= (hash
& mask
) + 1;
159 el
= st_array_at (ST_OBJECT_FIELDS (dict
)[2], i
);
160 if (el
== ST_NIL
|| el
== (uintptr_t) ST_OBJECT_FIELDS (dict
)[2])
162 if (machine
->message_selector
== ST_ASSOCIATION_KEY (el
))
163 return ST_ASSOCIATION_VALUE (el
);
164 i
= ((i
+ ST_ADVANCE_SIZE
) & mask
) + 1;
167 parent
= ST_BEHAVIOR_SUPERCLASS (parent
);
170 if (machine
->message_selector
== ST_SELECTOR_DOESNOTUNDERSTAND
) {
171 fprintf (stderr
, "panda: error: no method found for #doesNotUnderstand:\n");
175 create_actual_message (machine
);
177 return lookup_method (machine
, class);
181 st_machine_lookup_method (st_machine
*machine
, st_oop
class)
183 return lookup_method (machine
, class);
187 * Creates a new method context. Parameterised by
188 * @sender, @receiver, @method, and @argcount
190 * Message arguments are copied into the new context's temporary
191 * frame. Receiver and arguments are then popped off the stack.
195 activate_method (st_machine
*machine
)
200 context
= method_context_new (machine
);
202 arguments
= ST_METHOD_CONTEXT_STACK (context
);
203 for (st_uint i
= 0; i
< machine
->message_argcount
; i
++)
204 arguments
[i
] = machine
->stack
[machine
->sp
- machine
->message_argcount
+ i
];
206 machine
->sp
-= machine
->message_argcount
+ 1;
208 st_machine_set_active_context (machine
, context
);
212 st_machine_execute_method (st_machine
*machine
)
214 st_uint primitive_index
;
215 st_method_flags flags
;
217 flags
= st_method_get_flags (machine
->new_method
);
218 if (flags
== ST_METHOD_PRIMITIVE
) {
219 primitive_index
= st_method_get_primitive_index (machine
->new_method
);
220 machine
->success
= true;
221 st_primitives
[primitive_index
].func (machine
);
222 if (ST_LIKELY (machine
->success
))
226 activate_method (machine
);
230 st_machine_set_active_context (st_machine
*machine
, st_oop context
)
234 /* save executation state of active context */
235 if (ST_UNLIKELY (machine
->context
!= ST_NIL
)) {
236 ST_CONTEXT_PART_IP (machine
->context
) = st_smi_new (machine
->ip
);
237 ST_CONTEXT_PART_SP (machine
->context
) = st_smi_new (machine
->sp
);
240 if (ST_OBJECT_CLASS (context
) == ST_BLOCK_CONTEXT_CLASS
) {
241 home
= ST_BLOCK_CONTEXT_HOME (context
);
242 machine
->method
= ST_METHOD_CONTEXT_METHOD (home
);
243 machine
->receiver
= ST_METHOD_CONTEXT_RECEIVER (home
);
244 machine
->temps
= ST_METHOD_CONTEXT_STACK (home
);
245 machine
->stack
= ST_BLOCK_CONTEXT_STACK (context
);
247 machine
->method
= ST_METHOD_CONTEXT_METHOD (context
);
248 machine
->receiver
= ST_METHOD_CONTEXT_RECEIVER (context
);
249 machine
->temps
= ST_METHOD_CONTEXT_STACK (context
);
250 machine
->stack
= ST_METHOD_CONTEXT_STACK (context
);
253 machine
->context
= context
;
254 machine
->sp
= st_smi_value (ST_CONTEXT_PART_SP (context
));
255 machine
->ip
= st_smi_value (ST_CONTEXT_PART_IP (context
));
256 machine
->bytecode
= st_method_bytecode_bytes (machine
->method
);
259 #define SEND_SELECTOR(selector, argcount) \
260 machine->message_argcount = argcount; \
261 machine->message_receiver = sp[- argcount - 1]; \
262 machine->message_selector = selector; \
265 #define SEND_TEMPLATE() \
266 machine->lookup_class = st_object_class (machine->message_receiver); \
270 #ifdef HAVE_COMPUTED_GOTO
272 static const st_pointer labels[] = \
276 && PUSH_LITERAL_CONST, \
277 && PUSH_LITERAL_VAR, \
278 && STORE_LITERAL_VAR, \
281 && STORE_POP_LITERAL_VAR, \
283 && STORE_POP_INSTVAR, \
289 && RETURN_STACK_TOP, \
292 && DUPLICATE_STACK_TOP, \
293 && PUSH_ACTIVE_CONTEXT, \
320 && SEND_IDENTITY_EQ, \
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, && INVALID, && INVALID, && INVALID, && INVALID, \
364 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
374 #ifdef HAVE_COMPUTED_GOTO
375 #define INVALID() INVALID:
378 #define INVALID() default:
379 #define CASE(OP) case OP:
382 #ifdef HAVE_COMPUTED_GOTO
383 #define NEXT() goto *labels[*ip]
385 #define NEXT() goto start
389 install_method_in_cache (st_machine
*machine
)
393 index
= ST_METHOD_CACHE_HASH (machine
->lookup_class
, machine
->message_selector
) & ST_METHOD_CACHE_MASK
;
394 machine
->method_cache
[index
].class = machine
->lookup_class
;
395 machine
->method_cache
[index
].selector
= machine
->message_selector
;
396 machine
->method_cache
[index
].method
= machine
->new_method
;
400 lookup_method_in_cache (st_machine
*machine
)
404 index
= ST_METHOD_CACHE_HASH (machine
->lookup_class
, machine
->message_selector
) & ST_METHOD_CACHE_MASK
;
405 if (machine
->method_cache
[index
].class == machine
->lookup_class
&&
406 machine
->method_cache
[index
].selector
== machine
->message_selector
) {
407 machine
->new_method
= machine
->method_cache
[index
].method
;
413 #define STACK_POP(oop) (*--sp)
414 #define STACK_PUSH(oop) (*sp++ = (oop))
415 #define STACK_PEEK(oop) (*(sp-1))
416 #define STACK_UNPOP(count) (sp += count)
417 #define STORE_REGISTERS() \
418 machine->ip = ip - machine->bytecode; \
419 machine->sp = sp - machine->stack; \
420 ST_CONTEXT_PART_IP (machine->context) = st_smi_new (machine->ip);
421 #define LOAD_REGISTERS() \
422 ip = machine->bytecode + machine->ip; \
423 sp = machine->stack + machine->sp; \
424 ST_CONTEXT_PART_SP (machine->context) = st_smi_new (machine->sp);
427 st_machine_main (st_machine
*machine
)
429 register const st_uchar
*ip
;
430 register st_oop
*sp
= machine
->stack
;
432 if (setjmp (machine
->main_loop
))
435 ip
= machine
->bytecode
+ machine
->ip
;
441 STACK_PUSH (machine
->temps
[ip
[1]]);
447 CASE (PUSH_INSTVAR
) {
449 STACK_PUSH (ST_OBJECT_FIELDS (machine
->receiver
)[ip
[1]]);
455 CASE (STORE_POP_INSTVAR
) {
457 ST_OBJECT_FIELDS (machine
->receiver
)[ip
[1]] = STACK_POP ();
463 CASE (STORE_INSTVAR
) {
465 ST_OBJECT_FIELDS (machine
->receiver
)[ip
[1]] = STACK_PEEK ();
471 CASE (STORE_POP_TEMP
) {
473 machine
->temps
[ip
[1]] = STACK_POP ();
481 machine
->temps
[ip
[1]] = STACK_PEEK ();
487 CASE (STORE_LITERAL_VAR
) {
490 ST_ASSOCIATION_VALUE (st_array_elements (ST_METHOD_LITERALS (machine
->method
))[ip
[1]]) = STACK_PEEK ();
496 CASE (STORE_POP_LITERAL_VAR
) {
498 ST_ASSOCIATION_VALUE (st_array_elements (ST_METHOD_LITERALS (machine
->method
))[ip
[1]]) = STACK_POP ();
506 STACK_PUSH (machine
->receiver
);
514 STACK_PUSH (ST_TRUE
);
522 STACK_PUSH (ST_FALSE
);
536 CASE (PUSH_INTEGER
) {
538 STACK_PUSH (st_smi_new ((signed char) ip
[1]));
544 CASE (PUSH_ACTIVE_CONTEXT
) {
546 STACK_PUSH (machine
->context
);
552 CASE (PUSH_LITERAL_CONST
) {
554 STACK_PUSH (st_array_elements (ST_METHOD_LITERALS (machine
->method
))[ip
[1]]);
560 CASE (PUSH_LITERAL_VAR
) {
564 var
= ST_ASSOCIATION_VALUE (st_array_elements (ST_METHOD_LITERALS (machine
->method
))[ip
[1]]);
574 if (STACK_PEEK () == ST_TRUE
) {
576 ip
+= *((unsigned short *) (ip
+ 1)) + 3;
577 } else if (ST_LIKELY (STACK_PEEK () == ST_FALSE
)) {
582 SEND_SELECTOR (ST_SELECTOR_MUSTBEBOOLEAN
, 0);
591 if (STACK_PEEK () == ST_FALSE
) {
593 ip
+= *((unsigned short *) (ip
+ 1)) + 3;
594 } else if (ST_LIKELY (STACK_PEEK () == ST_TRUE
)) {
599 SEND_SELECTOR (ST_SELECTOR_MUSTBEBOOLEAN
, 0);
607 ip
+= *((short *) (ip
+ 1)) + 3;
615 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
616 st_object_is_smi (sp
[-2]))) {
617 b
= st_smi_value (sp
[-1]);
618 a
= st_smi_value (sp
[-2]);
620 if (((result
<< 1) ^ (result
<< 2)) >= 0) {
622 STACK_PUSH (st_smi_new (result
));
628 machine
->message_argcount
= 1;
629 machine
->message_selector
= ST_SELECTOR_PLUS
;
630 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
631 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
640 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
641 st_object_is_smi (sp
[-2]))) {
642 b
= st_smi_value (sp
[-1]);
643 a
= st_smi_value (sp
[-2]);
645 if (((result
<< 1) ^ (result
<< 2)) >= 0) {
647 STACK_PUSH (st_smi_new (result
));
655 machine
->message_argcount
= 1;
656 machine
->message_selector
= ST_SELECTOR_MINUS
;
657 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
658 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
668 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
669 st_object_is_smi (sp
[-2]))) {
670 b
= st_smi_value (sp
[-1]);
671 a
= st_smi_value (sp
[-2]);
673 if (result
>= ST_SMALL_INTEGER_MIN
&& result
<= ST_SMALL_INTEGER_MAX
) {
675 STACK_PUSH (st_smi_new ((int)result
));
681 machine
->message_argcount
= 1;
682 machine
->message_selector
= ST_SELECTOR_MUL
;
683 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
684 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
694 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
695 st_object_is_smi (sp
[-2]))) {
698 STACK_PUSH (st_smi_new (st_smi_value (a
) % st_smi_value (b
)));
703 machine
->message_argcount
= 1;
704 machine
->message_selector
= ST_SELECTOR_MOD
;
705 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
706 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
713 machine
->message_argcount
= 1;
714 machine
->message_selector
= ST_SELECTOR_DIV
;
715 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
716 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
721 CASE (SEND_BITSHIFT
) {
725 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
726 st_object_is_smi (sp
[-2]))) {
729 if (st_smi_value (b
) < 0) {
730 STACK_PUSH (st_smi_new (st_smi_value (a
) >> -st_smi_value (b
)));
732 STACK_PUSH (st_smi_new (st_smi_value (a
) << st_smi_value (b
)));
737 machine
->message_argcount
= 1;
738 machine
->message_selector
= ST_SELECTOR_BITSHIFT
;
739 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
740 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
749 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
750 st_object_is_smi (sp
[-2]))) {
753 STACK_PUSH (st_smi_new (st_smi_value (a
) & st_smi_value (b
)));
758 machine
->message_argcount
= 1;
759 machine
->message_selector
= ST_SELECTOR_BITAND
;
760 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
761 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
770 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
771 st_object_is_smi (sp
[-2]))) {
774 STACK_PUSH (st_smi_new (st_smi_value (a
) | st_smi_value (b
)));
779 machine
->message_argcount
= 1;
780 machine
->message_selector
= ST_SELECTOR_BITOR
;
781 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
782 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
792 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
793 st_object_is_smi (sp
[-2]))) {
796 STACK_PUSH (st_smi_new (st_smi_value (a
) ^ st_smi_value (b
)));
801 machine
->message_argcount
= 1;
802 machine
->message_selector
= ST_SELECTOR_BITXOR
;
803 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
804 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
813 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
814 st_object_is_smi (sp
[-2]))) {
817 STACK_PUSH (st_smi_value (a
) < st_smi_value (b
) ? ST_TRUE
: ST_FALSE
);
822 machine
->message_argcount
= 1;
823 machine
->message_selector
= ST_SELECTOR_LT
;
824 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
825 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
834 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
835 st_object_is_smi (sp
[-2]))) {
838 STACK_PUSH (st_smi_value (a
) > st_smi_value (b
) ? ST_TRUE
: ST_FALSE
);
843 machine
->message_argcount
= 1;
844 machine
->message_selector
= ST_SELECTOR_GT
;
845 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
846 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
856 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
857 st_object_is_smi (sp
[-2]))) {
860 STACK_PUSH (st_smi_value (a
) <= st_smi_value (b
) ? ST_TRUE
: ST_FALSE
);
865 machine
->message_argcount
= 1;
866 machine
->message_selector
= ST_SELECTOR_LE
;
867 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
868 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
877 if (ST_LIKELY (st_object_is_smi (sp
[-1]) &&
878 st_object_is_smi (sp
[-2]))) {
881 STACK_PUSH (st_smi_value (a
) >= st_smi_value (b
) ? ST_TRUE
: ST_FALSE
);
886 machine
->message_argcount
= 1;
887 machine
->message_selector
= ST_SELECTOR_GE
;
888 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
889 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
897 machine
->message_argcount
= 0;
898 machine
->message_selector
= ST_SELECTOR_CLASS
;
899 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
900 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
907 machine
->message_argcount
= 0;
908 machine
->message_selector
= ST_SELECTOR_SIZE
;
909 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
910 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
917 machine
->message_argcount
= 1;
918 machine
->message_selector
= ST_SELECTOR_AT
;
919 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
920 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
927 machine
->message_argcount
= 2;
928 machine
->message_selector
= ST_SELECTOR_ATPUT
;
929 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
930 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
937 machine
->message_argcount
= 1;
938 machine
->message_selector
= ST_SELECTOR_EQ
;
939 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
940 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
947 machine
->message_argcount
= 1;
948 machine
->message_selector
= ST_SELECTOR_NE
;
949 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
950 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
955 CASE (SEND_IDENTITY_EQ
) {
961 STACK_PUSH ((a
== b
) ? ST_TRUE
: ST_FALSE
);
969 machine
->message_argcount
= 0;
970 machine
->message_selector
= ST_SELECTOR_VALUE
;
971 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
972 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
977 CASE (SEND_VALUE_ARG
) {
979 machine
->message_argcount
= 1;
980 machine
->message_selector
= ST_SELECTOR_VALUE_ARG
;
981 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
982 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
989 machine
->message_argcount
= 0;
990 machine
->message_selector
= ST_SELECTOR_NEW
;
991 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
992 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
997 CASE (SEND_NEW_ARG
) {
999 machine
->message_argcount
= 1;
1000 machine
->message_selector
= ST_SELECTOR_NEW_ARG
;
1001 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
1002 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
1009 st_uint primitive_index
;
1010 st_method_flags flags
;
1014 machine
->message_argcount
= ip
[1];
1015 machine
->message_selector
= st_array_elements (ST_METHOD_LITERALS (machine
->method
))[ip
[2]];
1016 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
1017 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
1022 if (!lookup_method_in_cache (machine
)) {
1024 machine
->new_method
= lookup_method (machine
, machine
->lookup_class
);
1026 install_method_in_cache (machine
);
1029 flags
= st_method_get_flags (machine
->new_method
);
1030 if (flags
== ST_METHOD_PRIMITIVE
) {
1031 primitive_index
= st_method_get_primitive_index (machine
->new_method
);
1033 machine
->success
= true;
1035 st_primitives
[primitive_index
].func (machine
);
1038 if (ST_LIKELY (machine
->success
))
1042 /* store registers as a gc could occur */
1044 context
= method_context_new (machine
);
1046 arguments
= ST_METHOD_CONTEXT_STACK (context
);
1047 for (int i
= 0; i
< machine
->message_argcount
; i
++)
1048 arguments
[i
] = sp
[- machine
->message_argcount
+ i
];
1049 sp
-= machine
->message_argcount
+ 1;
1052 st_machine_set_active_context (machine
, context
);
1055 /* We have to nil these fields here. Its possible that
1056 that the objects they reference may be zapped by the gc.
1057 Another GC invocation may try to remap these fields not knowing that
1058 the references are invalid.
1059 FIXME: move this nilling out of such a critical execution path */
1060 machine
->message_receiver
= ST_NIL
;
1061 machine
->message_selector
= ST_NIL
;
1070 machine
->message_argcount
= ip
[1];
1071 machine
->message_selector
= st_array_elements (ST_METHOD_LITERALS (machine
->method
))[ip
[2]];
1072 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
1074 index
= st_smi_value (st_arrayed_object_size (ST_METHOD_LITERALS (machine
->method
))) - 1;
1075 machine
->lookup_class
= ST_BEHAVIOR_SUPERCLASS (st_array_elements (ST_METHOD_LITERALS (machine
->method
))[index
]);
1082 CASE (POP_STACK_TOP
) {
1084 (void) STACK_POP ();
1090 CASE (DUPLICATE_STACK_TOP
) {
1092 STACK_PUSH (STACK_PEEK ());
1102 st_uint argcount
= ip
[1];
1107 initial_ip
= ip
- machine
->bytecode
+ 3;
1110 block
= block_context_new (machine
, initial_ip
, argcount
);
1118 CASE (RETURN_STACK_TOP
) {
1124 value
= STACK_PEEK ();
1126 if (ST_OBJECT_CLASS (machine
->context
) == ST_BLOCK_CONTEXT_CLASS
)
1127 sender
= ST_CONTEXT_PART_SENDER (ST_BLOCK_CONTEXT_HOME (machine
->context
));
1129 sender
= ST_CONTEXT_PART_SENDER (machine
->context
);
1130 st_memory_recycle_context (machine
->context
);
1133 if (ST_UNLIKELY (sender
== ST_NIL
)) {
1134 STACK_PUSH (machine
->context
);
1136 SEND_SELECTOR (ST_SELECTOR_CANNOTRETURN
, 1);
1140 st_machine_set_active_context (machine
, sender
);
1147 CASE (BLOCK_RETURN
) {
1153 caller
= ST_CONTEXT_PART_SENDER (machine
->context
);
1154 value
= STACK_PEEK ();
1156 st_machine_set_active_context (machine
, caller
);
1170 st_log ("gc", "totalPauseTime: %.6fs\n",
1171 st_timespec_to_double_seconds (&memory
->total_pause_time
));
1175 st_machine_clear_caches (st_machine
*machine
)
1177 memset (machine
->method_cache
, 0, ST_METHOD_CACHE_SIZE
* 3 * sizeof (st_oop
));
1181 st_machine_initialize (st_machine
*machine
)
1186 /* clear contents */
1187 machine
->context
= ST_NIL
;
1188 machine
->receiver
= ST_NIL
;
1189 machine
->method
= ST_NIL
;
1193 machine
->stack
= NULL
;
1195 st_machine_clear_caches (machine
);
1197 machine
->message_argcount
= 0;
1198 machine
->message_receiver
= ST_SMALLTALK
;
1199 machine
->message_selector
= ST_SELECTOR_STARTUPSYSTEM
;
1201 machine
->new_method
= lookup_method (machine
, st_object_class (machine
->message_receiver
));
1202 st_assert (st_method_get_flags (machine
->new_method
) == ST_METHOD_NORMAL
);
1204 context
= method_context_new (machine
);
1205 st_machine_set_active_context (machine
, context
);