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 temp_count
= st_method_get_arg_count (machine
->new_method
) + st_method_get_temp_count (machine
->new_method
);
56 context
= st_memory_allocate_context ();
58 ST_CONTEXT_PART_SENDER (context
) = machine
->context
;
59 ST_CONTEXT_PART_IP (context
) = st_smi_new (0);
60 ST_CONTEXT_PART_SP (context
) = st_smi_new (temp_count
);
61 ST_METHOD_CONTEXT_RECEIVER (context
) = machine
->message_receiver
;
62 ST_METHOD_CONTEXT_METHOD (context
) = machine
->new_method
;
64 /* clear temporaries (and nothing above) */
65 stack
= ST_METHOD_CONTEXT_STACK (context
);
66 for (st_uint i
=0; i
< temp_count
; i
++)
73 block_context_new (st_machine
*machine
, st_uint initial_ip
, st_uint argcount
)
83 context
= st_memory_allocate (ST_SIZE_OOPS (struct st_block_context
) + stack_size
);
85 st_memory_perform_gc ();
86 context
= st_memory_allocate (ST_SIZE_OOPS (struct st_block_context
) + stack_size
);
87 st_assert (context
!= 0);
90 st_object_initialize_header (context
, ST_BLOCK_CONTEXT_CLASS
);
92 if (ST_OBJECT_CLASS (machine
->context
) == ST_BLOCK_CONTEXT_CLASS
)
93 home
= ST_BLOCK_CONTEXT_HOME (machine
->context
);
95 home
= machine
->context
;
97 ST_CONTEXT_PART_SENDER (context
) = ST_NIL
;
98 ST_CONTEXT_PART_IP (context
) = st_smi_new (0);
99 ST_CONTEXT_PART_SP (context
) = st_smi_new (0);
101 ST_BLOCK_CONTEXT_INITIALIP (context
) = st_smi_new (initial_ip
);
102 ST_BLOCK_CONTEXT_ARGCOUNT (context
) = st_smi_new (argcount
);
103 ST_BLOCK_CONTEXT_HOME (context
) = home
;
109 create_actual_message (st_machine
*machine
)
115 array
= st_object_new_arrayed (ST_ARRAY_CLASS
, machine
->message_argcount
);
116 elements
= st_array_elements (array
);
117 for (st_uint i
= 0; i
< machine
->message_argcount
; i
++)
118 elements
[i
] = machine
->stack
[machine
->sp
- machine
->message_argcount
+ i
];
120 machine
->sp
-= machine
->message_argcount
;
122 message
= st_object_new (ST_MESSAGE_CLASS
);
124 st_memory_perform_gc ();
125 message
= st_object_new (ST_MESSAGE_CLASS
);
126 st_assert (message
!= 0);
129 ST_OBJECT_FIELDS (message
)[0] = machine
->message_selector
;
130 ST_OBJECT_FIELDS (message
)[1] = array
;
132 ST_STACK_PUSH (machine
, message
);
134 machine
->message_selector
= ST_SELECTOR_DOESNOTUNDERSTAND
;
135 machine
->message_argcount
= 1;
139 lookup_method (st_machine
*machine
, st_oop
class)
141 st_oop method
, dict
, parent
;
145 hash
= st_byte_array_hash (machine
->message_selector
);
147 while (parent
!= ST_NIL
) {
152 dict
= ST_BEHAVIOR_METHOD_DICTIONARY (parent
);
153 mask
= st_smi_value (st_arrayed_object_size (ST_OBJECT_FIELDS (dict
)[2])) - 1;
154 i
= (hash
& mask
) + 1;
157 el
= st_array_at (ST_OBJECT_FIELDS (dict
)[2], i
);
158 if (el
== ST_NIL
|| el
== (uintptr_t) ST_OBJECT_FIELDS (dict
)[2])
160 if (machine
->message_selector
== ST_ASSOCIATION_KEY (el
))
161 return ST_ASSOCIATION_VALUE (el
);
162 i
= ((i
+ ST_ADVANCE_SIZE
) & mask
) + 1;
165 parent
= ST_BEHAVIOR_SUPERCLASS (parent
);
168 if (machine
->message_selector
== ST_SELECTOR_DOESNOTUNDERSTAND
) {
169 fprintf (stderr
, "panda: error: no method found for #doesNotUnderstand:\n");
173 create_actual_message (machine
);
175 return lookup_method (machine
, class);
179 st_machine_lookup_method (st_machine
*machine
, st_oop
class)
181 return lookup_method (machine
, class);
185 * Creates a new method context. Parameterised by
186 * @sender, @receiver, @method, and @argcount
188 * Message arguments are copied into the new context's temporary
189 * frame. Receiver and arguments are then popped off the stack.
193 activate_method (st_machine
*machine
)
198 context
= method_context_new (machine
);
200 arguments
= ST_METHOD_CONTEXT_STACK (context
);
201 for (st_uint i
= 0; i
< machine
->message_argcount
; i
++)
202 arguments
[i
] = machine
->stack
[machine
->sp
- machine
->message_argcount
+ i
];
204 machine
->sp
-= machine
->message_argcount
+ 1;
206 st_machine_set_active_context (machine
, context
);
210 st_machine_execute_method (st_machine
*machine
)
212 st_uint primitive_index
;
213 st_method_flags flags
;
215 flags
= st_method_get_flags (machine
->new_method
);
216 if (flags
== ST_METHOD_PRIMITIVE
) {
217 primitive_index
= st_method_get_primitive_index (machine
->new_method
);
218 machine
->success
= true;
219 st_primitives
[primitive_index
].func (machine
);
220 if (ST_LIKELY (machine
->success
))
224 activate_method (machine
);
228 st_machine_set_active_context (st_machine
*machine
, st_oop context
)
232 /* save executation state of active context */
233 if (ST_UNLIKELY (machine
->context
!= ST_NIL
)) {
234 ST_CONTEXT_PART_IP (machine
->context
) = st_smi_new (machine
->ip
);
235 ST_CONTEXT_PART_SP (machine
->context
) = st_smi_new (machine
->sp
);
238 if (ST_OBJECT_CLASS (context
) == ST_BLOCK_CONTEXT_CLASS
) {
239 home
= ST_BLOCK_CONTEXT_HOME (context
);
240 machine
->method
= ST_METHOD_CONTEXT_METHOD (home
);
241 machine
->receiver
= ST_METHOD_CONTEXT_RECEIVER (home
);
242 machine
->temps
= ST_METHOD_CONTEXT_STACK (home
);
243 machine
->stack
= ST_BLOCK_CONTEXT_STACK (context
);
245 machine
->method
= ST_METHOD_CONTEXT_METHOD (context
);
246 machine
->receiver
= ST_METHOD_CONTEXT_RECEIVER (context
);
247 machine
->temps
= ST_METHOD_CONTEXT_STACK (context
);
248 machine
->stack
= ST_METHOD_CONTEXT_STACK (context
);
251 machine
->context
= context
;
252 machine
->sp
= st_smi_value (ST_CONTEXT_PART_SP (context
));
253 machine
->ip
= st_smi_value (ST_CONTEXT_PART_IP (context
));
254 machine
->bytecode
= st_method_bytecode_bytes (machine
->method
);
257 #define SEND_SELECTOR(selector, argcount) \
258 machine->message_argcount = argcount; \
259 machine->message_receiver = sp[- argcount - 1]; \
260 machine->message_selector = selector; \
263 #define SEND_TEMPLATE() \
264 machine->lookup_class = st_object_class (machine->message_receiver); \
268 #ifdef HAVE_COMPUTED_GOTO
270 static const st_pointer labels[] = \
274 && PUSH_LITERAL_CONST, \
275 && PUSH_LITERAL_VAR, \
276 && STORE_LITERAL_VAR, \
279 && STORE_POP_LITERAL_VAR, \
281 && STORE_POP_INSTVAR, \
287 && RETURN_STACK_TOP, \
290 && DUPLICATE_STACK_TOP, \
291 && PUSH_ACTIVE_CONTEXT, \
318 && SEND_IDENTITY_EQ, \
322 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
323 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
324 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
325 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
326 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
327 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
328 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
329 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
330 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
331 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
332 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
333 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
334 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
335 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
336 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
337 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
338 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
339 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
340 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
341 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
342 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
343 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
344 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
345 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
346 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
347 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
348 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
349 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
350 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
351 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
352 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
353 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
354 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
355 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
356 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
357 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
358 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
359 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
360 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
361 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
362 && INVALID, && INVALID, && INVALID, && INVALID, && INVALID, \
372 #ifdef HAVE_COMPUTED_GOTO
373 #define INVALID() INVALID:
376 #define INVALID() default:
377 #define CASE(OP) case OP:
380 #ifdef HAVE_COMPUTED_GOTO
381 #define NEXT() goto *labels[*ip]
383 #define NEXT() goto start
387 install_method_in_cache (st_machine
*machine
)
391 index
= ST_METHOD_CACHE_HASH (machine
->lookup_class
, machine
->message_selector
) & ST_METHOD_CACHE_MASK
;
392 machine
->method_cache
[index
].class = machine
->lookup_class
;
393 machine
->method_cache
[index
].selector
= machine
->message_selector
;
394 machine
->method_cache
[index
].method
= machine
->new_method
;
398 lookup_method_in_cache (st_machine
*machine
)
402 index
= ST_METHOD_CACHE_HASH (machine
->lookup_class
, machine
->message_selector
) & ST_METHOD_CACHE_MASK
;
403 if (machine
->method_cache
[index
].class == machine
->lookup_class
&&
404 machine
->method_cache
[index
].selector
== machine
->message_selector
) {
405 machine
->new_method
= machine
->method_cache
[index
].method
;
411 #define STACK_POP(oop) (*--sp)
412 #define STACK_PUSH(oop) (*sp++ = (oop))
413 #define STACK_PEEK(oop) (*(sp-1))
414 #define STACK_UNPOP(count) (sp += count)
415 #define STORE_REGISTERS() \
416 machine->ip = ip - machine->bytecode; \
417 machine->sp = sp - machine->stack; \
418 ST_CONTEXT_PART_IP (machine->context) = st_smi_new (machine->ip);
419 #define LOAD_REGISTERS() \
420 ip = machine->bytecode + machine->ip; \
421 sp = machine->stack + machine->sp; \
422 ST_CONTEXT_PART_SP (machine->context) = st_smi_new (machine->sp);
425 st_machine_main (st_machine
*machine
)
427 register const st_uchar
*ip
;
428 register st_oop
*sp
= machine
->stack
;
430 if (setjmp (machine
->main_loop
))
433 ip
= machine
->bytecode
+ machine
->ip
;
439 STACK_PUSH (machine
->temps
[ip
[1]]);
445 CASE (PUSH_INSTVAR
) {
447 STACK_PUSH (ST_OBJECT_FIELDS (machine
->receiver
)[ip
[1]]);
453 CASE (STORE_POP_INSTVAR
) {
455 ST_OBJECT_FIELDS (machine
->receiver
)[ip
[1]] = STACK_POP ();
461 CASE (STORE_INSTVAR
) {
463 ST_OBJECT_FIELDS (machine
->receiver
)[ip
[1]] = STACK_PEEK ();
469 CASE (STORE_POP_TEMP
) {
471 machine
->temps
[ip
[1]] = STACK_POP ();
479 machine
->temps
[ip
[1]] = STACK_PEEK ();
485 CASE (STORE_LITERAL_VAR
) {
488 ST_ASSOCIATION_VALUE (st_array_elements (ST_METHOD_LITERALS (machine
->method
))[ip
[1]]) = STACK_PEEK ();
494 CASE (STORE_POP_LITERAL_VAR
) {
496 ST_ASSOCIATION_VALUE (st_array_elements (ST_METHOD_LITERALS (machine
->method
))[ip
[1]]) = STACK_POP ();
504 STACK_PUSH (machine
->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 (machine
->context
);
550 CASE (PUSH_LITERAL_CONST
) {
552 STACK_PUSH (st_array_elements (ST_METHOD_LITERALS (machine
->method
))[ip
[1]]);
558 CASE (PUSH_LITERAL_VAR
) {
562 var
= ST_ASSOCIATION_VALUE (st_array_elements (ST_METHOD_LITERALS (machine
->method
))[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 machine
->message_argcount
= 1;
627 machine
->message_selector
= ST_SELECTOR_PLUS
;
628 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
629 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
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 machine
->message_argcount
= 1;
654 machine
->message_selector
= ST_SELECTOR_MINUS
;
655 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
656 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
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 machine
->message_argcount
= 1;
680 machine
->message_selector
= ST_SELECTOR_MUL
;
681 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
682 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
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 machine
->message_argcount
= 1;
702 machine
->message_selector
= ST_SELECTOR_MOD
;
703 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
704 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
711 machine
->message_argcount
= 1;
712 machine
->message_selector
= ST_SELECTOR_DIV
;
713 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
714 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
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 machine
->message_argcount
= 1;
736 machine
->message_selector
= ST_SELECTOR_BITSHIFT
;
737 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
738 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
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 machine
->message_argcount
= 1;
757 machine
->message_selector
= ST_SELECTOR_BITAND
;
758 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
759 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
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 machine
->message_argcount
= 1;
778 machine
->message_selector
= ST_SELECTOR_BITOR
;
779 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
780 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
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 machine
->message_argcount
= 1;
800 machine
->message_selector
= ST_SELECTOR_BITXOR
;
801 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
802 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
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 machine
->message_argcount
= 1;
821 machine
->message_selector
= ST_SELECTOR_LT
;
822 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
823 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
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 machine
->message_argcount
= 1;
842 machine
->message_selector
= ST_SELECTOR_GT
;
843 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
844 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
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 machine
->message_argcount
= 1;
864 machine
->message_selector
= ST_SELECTOR_LE
;
865 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
866 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
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 machine
->message_argcount
= 1;
885 machine
->message_selector
= ST_SELECTOR_GE
;
886 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
887 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
895 machine
->message_argcount
= 0;
896 machine
->message_selector
= ST_SELECTOR_CLASS
;
897 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
898 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
905 machine
->message_argcount
= 0;
906 machine
->message_selector
= ST_SELECTOR_SIZE
;
907 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
908 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
915 machine
->message_argcount
= 1;
916 machine
->message_selector
= ST_SELECTOR_AT
;
917 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
918 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
925 machine
->message_argcount
= 2;
926 machine
->message_selector
= ST_SELECTOR_ATPUT
;
927 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
928 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
935 machine
->message_argcount
= 1;
936 machine
->message_selector
= ST_SELECTOR_EQ
;
937 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
938 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
945 machine
->message_argcount
= 1;
946 machine
->message_selector
= ST_SELECTOR_NE
;
947 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
948 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
953 CASE (SEND_IDENTITY_EQ
) {
959 STACK_PUSH ((a
== b
) ? ST_TRUE
: ST_FALSE
);
967 machine
->message_argcount
= 0;
968 machine
->message_selector
= ST_SELECTOR_VALUE
;
969 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
970 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
975 CASE (SEND_VALUE_ARG
) {
977 machine
->message_argcount
= 1;
978 machine
->message_selector
= ST_SELECTOR_VALUE_ARG
;
979 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
980 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
987 machine
->message_argcount
= 0;
988 machine
->message_selector
= ST_SELECTOR_NEW
;
989 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
990 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
995 CASE (SEND_NEW_ARG
) {
997 machine
->message_argcount
= 1;
998 machine
->message_selector
= ST_SELECTOR_NEW_ARG
;
999 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
1000 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
1007 st_uint primitive_index
;
1008 st_method_flags flags
;
1012 machine
->message_argcount
= ip
[1];
1013 machine
->message_selector
= st_array_elements (ST_METHOD_LITERALS (machine
->method
))[ip
[2]];
1014 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
1015 machine
->lookup_class
= st_object_class (machine
->message_receiver
);
1020 if (!lookup_method_in_cache (machine
)) {
1022 machine
->new_method
= lookup_method (machine
, machine
->lookup_class
);
1024 install_method_in_cache (machine
);
1027 flags
= st_method_get_flags (machine
->new_method
);
1028 if (flags
== ST_METHOD_PRIMITIVE
) {
1029 primitive_index
= st_method_get_primitive_index (machine
->new_method
);
1031 machine
->success
= true;
1033 st_primitives
[primitive_index
].func (machine
);
1036 if (ST_LIKELY (machine
->success
))
1040 /* store registers as a gc could occur */
1042 context
= method_context_new (machine
);
1044 arguments
= ST_METHOD_CONTEXT_STACK (context
);
1045 for (int i
= 0; i
< machine
->message_argcount
; i
++)
1046 arguments
[i
] = sp
[- machine
->message_argcount
+ i
];
1047 sp
-= machine
->message_argcount
+ 1;
1050 st_machine_set_active_context (machine
, 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 machine
->message_receiver
= ST_NIL
;
1059 machine
->message_selector
= ST_NIL
;
1068 machine
->message_argcount
= ip
[1];
1069 machine
->message_selector
= st_array_elements (ST_METHOD_LITERALS (machine
->method
))[ip
[2]];
1070 machine
->message_receiver
= sp
[- machine
->message_argcount
- 1];
1072 index
= st_smi_value (st_arrayed_object_size (ST_METHOD_LITERALS (machine
->method
))) - 1;
1073 machine
->lookup_class
= ST_BEHAVIOR_SUPERCLASS (st_array_elements (ST_METHOD_LITERALS (machine
->method
))[index
]);
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
- machine
->bytecode
+ 3;
1108 block
= block_context_new (machine
, initial_ip
, argcount
);
1116 CASE (RETURN_STACK_TOP
) {
1122 value
= STACK_PEEK ();
1124 if (ST_OBJECT_CLASS (machine
->context
) == ST_BLOCK_CONTEXT_CLASS
)
1125 sender
= ST_CONTEXT_PART_SENDER (ST_BLOCK_CONTEXT_HOME (machine
->context
));
1127 sender
= ST_CONTEXT_PART_SENDER (machine
->context
);
1128 st_memory_recycle_context (machine
->context
);
1131 if (ST_UNLIKELY (sender
== ST_NIL
)) {
1132 STACK_PUSH (machine
->context
);
1134 SEND_SELECTOR (ST_SELECTOR_CANNOTRETURN
, 1);
1138 st_machine_set_active_context (machine
, sender
);
1145 CASE (BLOCK_RETURN
) {
1151 caller
= ST_CONTEXT_PART_SENDER (machine
->context
);
1152 value
= STACK_PEEK ();
1154 st_machine_set_active_context (machine
, caller
);
1168 st_log ("gc", "totalPauseTime: %.6fs\n",
1169 st_timespec_to_double_seconds (&memory
->total_pause_time
));
1173 st_machine_clear_caches (st_machine
*machine
)
1175 memset (machine
->method_cache
, 0, ST_METHOD_CACHE_SIZE
* 3 * sizeof (st_oop
));
1179 st_machine_initialize (st_machine
*machine
)
1184 /* clear contents */
1185 machine
->context
= ST_NIL
;
1186 machine
->receiver
= ST_NIL
;
1187 machine
->method
= ST_NIL
;
1191 machine
->stack
= NULL
;
1193 st_machine_clear_caches (machine
);
1195 machine
->message_argcount
= 0;
1196 machine
->message_receiver
= ST_SMALLTALK
;
1197 machine
->message_selector
= ST_SELECTOR_STARTUPSYSTEM
;
1199 machine
->new_method
= lookup_method (machine
, st_object_class (machine
->message_receiver
));
1200 st_assert (st_method_get_flags (machine
->new_method
) == ST_METHOD_NORMAL
);
1202 context
= method_context_new (machine
);
1203 st_machine_set_active_context (machine
, context
);