update credits
[librepilot.git] / flight / libraries / PyMite / vm / interp.c
blob3c4ef33ecc7d6838dbc64103cd4d9d544fa33090
1 /*
2 # This file is Copyright 2003, 2006, 2007, 2009, 2010 Dean Hall.
4 # This file is part of the PyMite VM.
5 # The PyMite VM is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU GENERAL PUBLIC LICENSE Version 2.
8 # The PyMite VM is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 # A copy of the GNU GENERAL PUBLIC LICENSE Version 2
12 # is seen in the file COPYING in this directory.
16 #undef __FILE_ID__
17 #define __FILE_ID__ 0x09
20 /**
21 * \file
22 * \brief VM Interpreter
24 * VM interpreter operations.
28 #include "pm.h"
31 PmReturn_t
32 interpret(const uint8_t returnOnNoThreads)
34 PmReturn_t retval = PM_RET_OK;
35 pPmObj_t pobj1 = C_NULL;
36 pPmObj_t pobj2 = C_NULL;
37 pPmObj_t pobj3 = C_NULL;
38 int16_t t16 = 0;
39 int8_t t8 = 0;
40 uint8_t bc;
41 uint8_t objid, objid2;
43 /* Activate a thread the first time */
44 retval = interp_reschedule();
45 PM_RETURN_IF_ERROR(retval);
47 /* Interpret loop */
48 for (;;)
50 if (gVmGlobal.pthread == C_NULL)
52 if (returnOnNoThreads)
54 /* User chose to return on no threads left */
55 return retval;
59 * Without a frame there is nothing to execute, so reschedule
60 * (possibly activating a recently added thread).
62 retval = interp_reschedule();
63 PM_BREAK_IF_ERROR(retval);
64 continue;
67 /* Reschedule threads if flag is true? */
68 if (gVmGlobal.reschedule)
70 retval = interp_reschedule();
71 PM_BREAK_IF_ERROR(retval);
74 /* Get byte; the func post-incrs PM_IP */
75 bc = mem_getByte(PM_FP->fo_memspace, &PM_IP);
76 switch (bc)
78 case POP_TOP:
79 pobj1 = PM_POP();
80 continue;
82 case ROT_TWO:
83 pobj1 = TOS;
84 TOS = TOS1;
85 TOS1 = pobj1;
86 continue;
88 case ROT_THREE:
89 pobj1 = TOS;
90 TOS = TOS1;
91 TOS1 = TOS2;
92 TOS2 = pobj1;
93 continue;
95 case DUP_TOP:
96 pobj1 = TOS;
97 PM_PUSH(pobj1);
98 continue;
100 case ROT_FOUR:
101 pobj1 = TOS;
102 TOS = TOS1;
103 TOS1 = TOS2;
104 TOS2 = TOS3;
105 TOS3 = pobj1;
106 continue;
108 case NOP:
109 continue;
111 case UNARY_POSITIVE:
112 /* Raise TypeError if TOS is not an int */
113 if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
114 #ifdef HAVE_FLOAT
115 && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_FLT)
116 #endif /* HAVE_FLOAT */
119 PM_RAISE(retval, PM_RET_EX_TYPE);
120 break;
123 /* When TOS is an int, this is a no-op */
124 continue;
126 case UNARY_NEGATIVE:
127 #ifdef HAVE_FLOAT
128 if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
130 retval = float_negative(TOS, &pobj2);
132 else
133 #endif /* HAVE_FLOAT */
135 retval = int_negative(TOS, &pobj2);
137 PM_BREAK_IF_ERROR(retval);
138 TOS = pobj2;
139 continue;
141 case UNARY_NOT:
142 pobj1 = PM_POP();
143 if (obj_isFalse(pobj1))
145 PM_PUSH(PM_TRUE);
147 else
149 PM_PUSH(PM_FALSE);
151 continue;
153 #ifdef HAVE_BACKTICK
154 /* #244 Add support for the backtick operation (UNARY_CONVERT) */
155 case UNARY_CONVERT:
156 retval = obj_repr(TOS, &pobj3);
157 PM_BREAK_IF_ERROR(retval);
158 TOS = pobj3;
159 continue;
160 #endif /* HAVE_BACKTICK */
162 case UNARY_INVERT:
163 /* Raise TypeError if it's not an int */
164 if (OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
166 PM_RAISE(retval, PM_RET_EX_TYPE);
167 break;
170 /* Otherwise perform bit-wise complement */
171 retval = int_bitInvert(TOS, &pobj2);
172 PM_BREAK_IF_ERROR(retval);
173 TOS = pobj2;
174 continue;
176 case LIST_APPEND:
177 /* list_append will raise a TypeError if TOS1 is not a list */
178 retval = list_append(TOS1, TOS);
179 PM_SP -= 2;
180 continue;
182 case BINARY_POWER:
183 case INPLACE_POWER:
185 #ifdef HAVE_FLOAT
186 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
187 || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
189 /* Calculate float power */
190 retval = float_op(TOS1, TOS, &pobj3, 'P');
191 PM_BREAK_IF_ERROR(retval);
192 PM_SP--;
193 TOS = pobj3;
194 continue;
196 #endif /* HAVE_FLOAT */
198 /* Calculate integer power */
199 retval = int_pow(TOS1, TOS, &pobj3);
200 PM_BREAK_IF_ERROR(retval);
202 /* Set return value */
203 PM_SP--;
204 TOS = pobj3;
205 continue;
207 case GET_ITER:
208 #ifdef HAVE_GENERATORS
209 /* Raise TypeError if TOS is an instance, but not iterable */
210 if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
212 retval = class_getAttr(TOS, PM_NEXT_STR, &pobj1);
213 if (retval != PM_RET_OK)
215 PM_RAISE(retval, PM_RET_EX_TYPE);
216 break;
219 else
220 #endif /* HAVE_GENERATORS */
222 /* Convert sequence to sequence-iterator */
223 retval = seqiter_new(TOS, &pobj1);
224 PM_BREAK_IF_ERROR(retval);
226 /* Put sequence-iterator on top of stack */
227 TOS = pobj1;
229 continue;
231 case BINARY_MULTIPLY:
232 case INPLACE_MULTIPLY:
233 /* If both objs are ints, perform the op */
234 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
235 && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
237 retval = int_new(((pPmInt_t)TOS1)->val *
238 ((pPmInt_t)TOS)->val, &pobj3);
239 PM_BREAK_IF_ERROR(retval);
240 PM_SP--;
241 TOS = pobj3;
242 continue;
245 #ifdef HAVE_FLOAT
246 else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
247 || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
249 retval = float_op(TOS1, TOS, &pobj3, '*');
250 PM_BREAK_IF_ERROR(retval);
251 PM_SP--;
252 TOS = pobj3;
253 continue;
255 #endif /* HAVE_FLOAT */
257 #ifdef HAVE_REPLICATION
258 /* If it's a list replication operation */
259 else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
260 && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_LST))
262 t16 = (int16_t)((pPmInt_t)TOS)->val;
263 if (t16 < 0)
265 t16 = 0;
268 retval = list_replicate(TOS1, t16, &pobj3);
269 PM_BREAK_IF_ERROR(retval);
270 PM_SP--;
271 TOS = pobj3;
272 continue;
275 /* If it's a tuple replication operation */
276 else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
277 && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_TUP))
279 t16 = (int16_t)((pPmInt_t)TOS)->val;
280 if (t16 < 0)
282 t16 = 0;
285 retval = tuple_replicate(TOS1, t16, &pobj3);
286 PM_BREAK_IF_ERROR(retval);
287 PM_SP--;
288 TOS = pobj3;
289 continue;
292 /* If it's a string replication operation */
293 else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
294 && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_STR))
296 t16 = (int16_t)((pPmInt_t)TOS)->val;
297 if (t16 < 0)
299 t16 = 0;
302 pobj2 = TOS1;
303 pobj2 = (pPmObj_t)&((pPmString_t)pobj2)->val;
304 retval = string_replicate(
305 (uint8_t const **)(uint8_t *)&pobj2, t16, &pobj3);
306 PM_BREAK_IF_ERROR(retval);
307 PM_SP--;
308 TOS = pobj3;
309 continue;
311 #endif /* HAVE_REPLICATION */
313 /* Otherwise raise a TypeError */
314 PM_RAISE(retval, PM_RET_EX_TYPE);
315 break;
317 case BINARY_DIVIDE:
318 case INPLACE_DIVIDE:
319 case BINARY_FLOOR_DIVIDE:
320 case INPLACE_FLOOR_DIVIDE:
322 #ifdef HAVE_FLOAT
323 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
324 || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
326 retval = float_op(TOS1, TOS, &pobj3, '/');
327 PM_BREAK_IF_ERROR(retval);
328 PM_SP--;
329 TOS = pobj3;
330 continue;
332 #endif /* HAVE_FLOAT */
334 /* Raise TypeError if args aren't ints */
335 if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
336 || (OBJ_GET_TYPE(TOS1) != OBJ_TYPE_INT))
338 PM_RAISE(retval, PM_RET_EX_TYPE);
339 break;
342 /* Raise ZeroDivisionError if denominator is zero */
343 if (((pPmInt_t)TOS)->val == 0)
345 PM_RAISE(retval, PM_RET_EX_ZDIV);
346 break;
349 /* Otherwise perform operation */
350 retval = int_new(((pPmInt_t)TOS1)->val /
351 ((pPmInt_t)TOS)->val, &pobj3);
352 PM_BREAK_IF_ERROR(retval);
353 PM_SP--;
354 TOS = pobj3;
355 continue;
357 case BINARY_MODULO:
358 case INPLACE_MODULO:
360 #ifdef HAVE_STRING_FORMAT
361 /* If it's a string, perform string format */
362 if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_STR)
364 retval = string_format((pPmString_t)TOS1, TOS, &pobj3);
365 PM_BREAK_IF_ERROR(retval);
366 PM_SP--;
367 TOS = pobj3;
368 continue;
370 #endif /* HAVE_STRING_FORMAT */
372 #ifdef HAVE_FLOAT
373 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
374 || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
376 retval = float_op(TOS1, TOS, &pobj3, '%');
377 PM_BREAK_IF_ERROR(retval);
378 PM_SP--;
379 TOS = pobj3;
380 continue;
382 #endif /* HAVE_FLOAT */
384 /* Raise TypeError if args aren't ints */
385 if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
386 || (OBJ_GET_TYPE(TOS1) != OBJ_TYPE_INT))
388 PM_RAISE(retval, PM_RET_EX_TYPE);
389 break;
392 /* Raise ZeroDivisionError if denominator is zero */
393 if (((pPmInt_t)TOS)->val == 0)
395 PM_RAISE(retval, PM_RET_EX_ZDIV);
396 break;
399 /* Otherwise perform operation */
400 retval = int_new(((pPmInt_t)TOS1)->val %
401 ((pPmInt_t)TOS)->val, &pobj3);
402 PM_BREAK_IF_ERROR(retval);
403 PM_SP--;
404 TOS = pobj3;
405 continue;
407 case STORE_MAP:
408 /* #213: Add support for Python 2.6 bytecodes */
409 C_ASSERT(OBJ_GET_TYPE(TOS2) == OBJ_TYPE_DIC);
410 retval = dict_setItem(TOS2, TOS, TOS1);
411 PM_BREAK_IF_ERROR(retval);
412 PM_SP -= 2;
413 continue;
415 case BINARY_ADD:
416 case INPLACE_ADD:
418 #ifdef HAVE_FLOAT
419 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
420 || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
422 retval = float_op(TOS1, TOS, &pobj3, '+');
423 PM_BREAK_IF_ERROR(retval);
424 PM_SP--;
425 TOS = pobj3;
426 continue;
428 #endif /* HAVE_FLOAT */
430 /* If both objs are ints, perform the op */
431 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
432 && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
434 retval = int_new(((pPmInt_t)TOS1)->val +
435 ((pPmInt_t)TOS)->val, &pobj3);
436 PM_BREAK_IF_ERROR(retval);
437 PM_SP--;
438 TOS = pobj3;
439 continue;
442 /* #242: If both objs are strings, perform concatenation */
443 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_STR)
444 && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_STR))
446 retval = string_concat((pPmString_t)TOS1,
447 (pPmString_t)TOS,
448 &pobj3);
449 PM_BREAK_IF_ERROR(retval);
450 PM_SP--;
451 TOS = pobj3;
452 continue;
455 /* Otherwise raise a TypeError */
456 PM_RAISE(retval, PM_RET_EX_TYPE);
457 break;
459 case BINARY_SUBTRACT:
460 case INPLACE_SUBTRACT:
462 #ifdef HAVE_FLOAT
463 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
464 || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
466 retval = float_op(TOS1, TOS, &pobj3, '-');
467 PM_BREAK_IF_ERROR(retval);
468 PM_SP--;
469 TOS = pobj3;
470 continue;
472 #endif /* HAVE_FLOAT */
474 /* If both objs are ints, perform the op */
475 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
476 && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
478 retval = int_new(((pPmInt_t)TOS1)->val -
479 ((pPmInt_t)TOS)->val, &pobj3);
480 PM_BREAK_IF_ERROR(retval);
481 PM_SP--;
482 TOS = pobj3;
483 continue;
486 /* Otherwise raise a TypeError */
487 PM_RAISE(retval, PM_RET_EX_TYPE);
488 break;
490 case BINARY_SUBSCR:
491 /* Implements TOS = TOS1[TOS]. */
493 if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_DIC)
495 retval = dict_getItem(TOS1, TOS, &pobj3);
497 else
499 /* Raise a TypeError if index is not an Integer or Bool */
500 if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
501 && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_BOOL))
503 PM_RAISE(retval, PM_RET_EX_TYPE);
504 break;
507 pobj1 = TOS1;
508 #ifdef HAVE_BYTEARRAY
509 /* If object is an instance, get the thing it contains */
510 if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_CLI)
512 retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj1)->cli_attrs,
513 PM_NONE,
514 &pobj2);
515 PM_RETURN_IF_ERROR(retval);
516 pobj1 = pobj2;
518 #endif /* HAVE_BYTEARRAY */
520 /* Ensure the index doesn't overflow */
521 C_ASSERT(((pPmInt_t)TOS)->val <= 0x0000FFFF);
522 t16 = (int16_t)((pPmInt_t)TOS)->val;
524 retval = seq_getSubscript(pobj1, t16, &pobj3);
526 PM_BREAK_IF_ERROR(retval);
527 PM_SP--;
528 TOS = pobj3;
529 continue;
531 #ifdef HAVE_FLOAT
532 /* #213: Add support for Python 2.6 bytecodes */
533 case BINARY_TRUE_DIVIDE:
534 case INPLACE_TRUE_DIVIDE:
536 /* Perform division; float_op() checks for types and zero-div */
537 retval = float_op(TOS1, TOS, &pobj3, '/');
538 PM_BREAK_IF_ERROR(retval);
539 PM_SP--;
540 TOS = pobj3;
541 continue;
542 #endif /* HAVE_FLOAT */
544 case SLICE_0:
545 /* Implements TOS = TOS[:], push a copy of the sequence */
547 /* Create a copy if it is a list */
548 if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_LST)
550 retval = list_copy(TOS, &pobj2);
551 PM_BREAK_IF_ERROR(retval);
553 TOS = pobj2;
556 /* If TOS is an immutable sequence leave it (no op) */
558 /* Raise a TypeError for types that can not be sliced */
559 else if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_STR)
560 && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_TUP))
562 PM_RAISE(retval, PM_RET_EX_TYPE);
563 break;
565 continue;
567 case STORE_SUBSCR:
568 /* Implements TOS1[TOS] = TOS2 */
570 /* If it's a list */
571 if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_LST)
573 /* Ensure subscr is an int or bool */
574 if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
575 && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_BOOL))
577 PM_RAISE(retval, PM_RET_EX_TYPE);
578 break;
581 /* Set the list item */
582 retval = list_setItem(TOS1,
583 (int16_t)(((pPmInt_t)TOS)->val),
584 TOS2);
585 PM_BREAK_IF_ERROR(retval);
586 PM_SP -= 3;
587 continue;
590 /* If it's a dict */
591 if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_DIC)
593 /* Set the dict item */
594 retval = dict_setItem(TOS1, TOS, TOS2);
595 PM_BREAK_IF_ERROR(retval);
596 PM_SP -= 3;
597 continue;
600 #ifdef HAVE_BYTEARRAY
601 /* If object is an instance, get the thing it contains */
602 if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_CLI)
604 retval = dict_getItem((pPmObj_t)((pPmInstance_t)TOS1)->cli_attrs,
605 PM_NONE,
606 &pobj2);
608 /* Raise TypeError if instance isn't a ByteArray */
609 if ((retval == PM_RET_EX_KEY)
610 || (OBJ_GET_TYPE(pobj2) != OBJ_TYPE_BYA))
612 PM_RAISE(retval, PM_RET_EX_TYPE);
613 break;
615 PM_BREAK_IF_ERROR(retval);
617 /* Ensure subscr is an int or bool */
618 if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
619 && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_BOOL))
621 PM_RAISE(retval, PM_RET_EX_TYPE);
622 break;
625 retval = bytearray_setItem(pobj2,
626 (int16_t)(((pPmInt_t)TOS)->val),
627 TOS2);
628 PM_BREAK_IF_ERROR(retval);
629 PM_SP -= 3;
630 continue;
632 #endif /* HAVE_BYTEARRAY */
634 /* TypeError for all else */
635 PM_RAISE(retval, PM_RET_EX_TYPE);
636 break;
638 #ifdef HAVE_DEL
639 case DELETE_SUBSCR:
641 if ((OBJ_GET_TYPE(TOS1) == OBJ_TYPE_LST)
642 && (OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT))
644 retval = list_delItem(TOS1,
645 (int16_t)((pPmInt_t)TOS)->val);
648 else if ((OBJ_GET_TYPE(TOS1) == OBJ_TYPE_DIC)
649 && (OBJ_GET_TYPE(TOS) <= OBJ_TYPE_HASHABLE_MAX))
651 retval = dict_delItem(TOS1, TOS);
654 /* Raise TypeError if obj is not a list or dict */
655 else
657 PM_RAISE(retval, PM_RET_EX_TYPE);
660 PM_BREAK_IF_ERROR(retval);
661 PM_SP -= 2;
662 continue;
663 #endif /* HAVE_DEL */
665 case BINARY_LSHIFT:
666 case INPLACE_LSHIFT:
667 /* If both objs are ints, perform the op */
668 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
669 && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
671 retval = int_new(((pPmInt_t)TOS1)->val <<
672 ((pPmInt_t)TOS)->val, &pobj3);
673 PM_BREAK_IF_ERROR(retval);
674 PM_SP--;
675 TOS = pobj3;
676 continue;
679 /* Otherwise raise a TypeError */
680 PM_RAISE(retval, PM_RET_EX_TYPE);
681 break;
683 case BINARY_RSHIFT:
684 case INPLACE_RSHIFT:
685 /* If both objs are ints, perform the op */
686 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
687 && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
689 retval = int_new(((pPmInt_t)TOS1)->val >>
690 ((pPmInt_t)TOS)->val, &pobj3);
691 PM_BREAK_IF_ERROR(retval);
692 PM_SP--;
693 TOS = pobj3;
694 continue;
697 /* Otherwise raise a TypeError */
698 PM_RAISE(retval, PM_RET_EX_TYPE);
699 break;
701 case BINARY_AND:
702 case INPLACE_AND:
703 /* If both objs are ints, perform the op */
704 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
705 && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
707 retval = int_new(((pPmInt_t)TOS1)->val &
708 ((pPmInt_t)TOS)->val, &pobj3);
709 PM_BREAK_IF_ERROR(retval);
710 PM_SP--;
711 TOS = pobj3;
712 continue;
715 /* Otherwise raise a TypeError */
716 PM_RAISE(retval, PM_RET_EX_TYPE);
717 break;
719 case BINARY_XOR:
720 case INPLACE_XOR:
721 /* If both objs are ints, perform the op */
722 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
723 && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
725 retval = int_new(((pPmInt_t)TOS1)->val ^
726 ((pPmInt_t)TOS)->val, &pobj3);
727 PM_BREAK_IF_ERROR(retval);
728 PM_SP--;
729 TOS = pobj3;
730 continue;
733 /* Otherwise raise a TypeError */
734 PM_RAISE(retval, PM_RET_EX_TYPE);
735 break;
737 case BINARY_OR:
738 case INPLACE_OR:
739 /* If both objs are ints, perform the op */
740 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
741 && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
743 retval = int_new(((pPmInt_t)TOS1)->val |
744 ((pPmInt_t)TOS)->val, &pobj3);
745 PM_BREAK_IF_ERROR(retval);
746 PM_SP--;
747 TOS = pobj3;
748 continue;
751 /* Otherwise raise a TypeError */
752 PM_RAISE(retval, PM_RET_EX_TYPE);
753 break;
755 #ifdef HAVE_PRINT
756 case PRINT_EXPR:
757 /* Print interactive expression */
758 /* Fallthrough */
760 case PRINT_ITEM:
761 if (gVmGlobal.needSoftSpace && (bc == PRINT_ITEM))
763 retval = plat_putByte(' ');
764 PM_BREAK_IF_ERROR(retval);
766 gVmGlobal.needSoftSpace = C_TRUE;
768 /* Print out topmost stack element */
769 retval = obj_print(TOS, (uint8_t)(bc == PRINT_EXPR), C_FALSE);
770 PM_BREAK_IF_ERROR(retval);
771 PM_SP--;
772 if (bc != PRINT_EXPR)
774 continue;
776 /* If PRINT_EXPR, Fallthrough to print a newline */
778 case PRINT_NEWLINE:
779 gVmGlobal.needSoftSpace = C_FALSE;
780 if (gVmGlobal.somethingPrinted)
782 retval = plat_putByte('\n');
783 gVmGlobal.somethingPrinted = C_FALSE;
785 PM_BREAK_IF_ERROR(retval);
786 continue;
787 #endif /* HAVE_PRINT */
789 case BREAK_LOOP:
791 pPmBlock_t pb1 = PM_FP->fo_blockstack;
793 /* Ensure there's a block */
794 C_ASSERT(pb1 != C_NULL);
796 /* Delete blocks until first loop block */
797 while ((pb1->b_type != B_LOOP) && (pb1->next != C_NULL))
799 pobj2 = (pPmObj_t)pb1;
800 pb1 = pb1->next;
801 retval = heap_freeChunk(pobj2);
802 PM_BREAK_IF_ERROR(retval);
805 /* Test again outside while loop */
806 PM_BREAK_IF_ERROR(retval);
808 /* Restore PM_SP */
809 PM_SP = pb1->b_sp;
811 /* Goto handler */
812 PM_IP = pb1->b_handler;
814 /* Pop and delete this block */
815 PM_FP->fo_blockstack = pb1->next;
816 retval = heap_freeChunk((pPmObj_t)pb1);
817 PM_BREAK_IF_ERROR(retval);
819 continue;
821 case LOAD_LOCALS:
822 /* Pushes local attrs dict of current frame */
823 /* WARNING: does not copy fo_locals to attrs */
824 PM_PUSH((pPmObj_t)PM_FP->fo_attrs);
825 continue;
827 case RETURN_VALUE:
828 /* Get expiring frame's TOS */
829 pobj2 = PM_POP();
831 #if 0 /*__DEBUG__*/
832 /* #251: This safety check is disabled because it breaks ipm */
833 /* #109: Check that stack should now be empty */
834 /* If this is regular frame (not native and not a generator) */
835 if ((PM_FP != (pPmFrame_t)(&gVmGlobal.nativeframe)) &&
836 !(PM_FP->fo_func->f_co->co_flags & CO_GENERATOR))
838 /* An empty stack points one past end of locals */
839 t8 = PM_FP->fo_func->f_co->co_nlocals;
840 C_ASSERT(PM_SP == &(PM_FP->fo_locals[t8]));
842 #endif /* __DEBUG__ */
844 /* Keep ref of expiring frame */
845 pobj1 = (pPmObj_t)PM_FP;
846 C_ASSERT(OBJ_GET_TYPE(pobj1) == OBJ_TYPE_FRM);
848 /* If no previous frame, quit thread */
849 if (PM_FP->fo_back == C_NULL)
851 gVmGlobal.pthread->interpctrl = INTERP_CTRL_EXIT;
852 retval = PM_RET_OK;
853 break;
856 /* Otherwise return to previous frame */
857 PM_FP = PM_FP->fo_back;
859 #ifdef HAVE_GENERATORS
860 /* If returning function was a generator */
861 if (((pPmFrame_t)pobj1)->fo_func->f_co->co_flags & CO_GENERATOR)
863 /* Raise a StopIteration exception */
864 PM_RAISE(retval, PM_RET_EX_STOP);
865 break;
867 #endif /* HAVE_GENERATORS */
869 #ifdef HAVE_CLASSES
871 * If returning function was class initializer
872 * do not push a return object
874 if (((pPmFrame_t)pobj1)->fo_isInit)
876 /* Raise TypeError if __init__ did not return None */
877 if (pobj2 != PM_NONE)
879 PM_RAISE(retval, PM_RET_EX_TYPE);
880 break;
883 else
884 #endif /* HAVE_CLASSES */
887 * Push frame's return val, except if the expiring frame
888 * was due to an import statement
890 if (!(((pPmFrame_t)pobj1)->fo_isImport))
892 PM_PUSH(pobj2);
895 /* Deallocate expired frame */
896 PM_BREAK_IF_ERROR(heap_freeChunk(pobj1));
897 continue;
899 #ifdef HAVE_IMPORTS
900 case IMPORT_STAR:
901 /* #102: Implement the remaining IMPORT_ bytecodes */
902 /* Expect a module on the top of the stack */
903 C_ASSERT(OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD);
905 /* Update PM_FP's attrs with those of the module on the stack */
906 retval = dict_update((pPmObj_t)PM_FP->fo_attrs,
907 (pPmObj_t)((pPmFunc_t)TOS)->f_attrs);
908 PM_BREAK_IF_ERROR(retval);
909 PM_SP--;
910 continue;
911 #endif /* HAVE_IMPORTS */
913 #ifdef HAVE_GENERATORS
914 case YIELD_VALUE:
915 /* #207: Add support for the yield keyword */
916 /* Get expiring frame's TOS */
917 pobj1 = PM_POP();
919 /* Raise TypeError if __init__ did not return None */
920 /* (Yield means this is a generator) */
921 if ((PM_FP)->fo_isInit)
923 PM_RAISE(retval, PM_RET_EX_TYPE);
924 break;
927 /* Return to previous frame */
928 PM_FP = PM_FP->fo_back;
930 /* Push yield value onto caller's TOS */
931 PM_PUSH(pobj1);
932 continue;
933 #endif /* HAVE_GENERATORS */
935 case POP_BLOCK:
936 /* Get ptr to top block */
937 pobj1 = (pPmObj_t)PM_FP->fo_blockstack;
939 /* If there's no block, raise SystemError */
940 C_ASSERT(pobj1 != C_NULL);
942 /* Pop block */
943 PM_FP->fo_blockstack = PM_FP->fo_blockstack->next;
945 /* Set stack to previous level, jump to code outside block */
946 PM_SP = ((pPmBlock_t)pobj1)->b_sp;
947 PM_IP = ((pPmBlock_t)pobj1)->b_handler;
949 PM_BREAK_IF_ERROR(heap_freeChunk(pobj1));
950 continue;
952 #ifdef HAVE_CLASSES
953 case BUILD_CLASS:
954 /* Create and push new class */
955 retval = class_new(TOS, TOS1, TOS2, &pobj2);
956 PM_BREAK_IF_ERROR(retval);
957 PM_SP -= 2;
958 TOS = pobj2;
959 continue;
960 #endif /* HAVE_CLASSES */
963 /***************************************************
964 * All bytecodes after 90 (0x5A) have a 2-byte arg
965 * that needs to be swallowed using GET_ARG().
966 **************************************************/
968 case STORE_NAME:
969 /* Get name index */
970 t16 = GET_ARG();
972 /* Get key */
973 pobj2 = PM_FP->fo_func->f_co->co_names->val[t16];
975 /* Set key=val in current frame's attrs dict */
976 retval = dict_setItem((pPmObj_t)PM_FP->fo_attrs, pobj2, TOS);
977 PM_BREAK_IF_ERROR(retval);
978 PM_SP--;
979 continue;
981 #ifdef HAVE_DEL
982 case DELETE_NAME:
983 /* Get name index */
984 t16 = GET_ARG();
986 /* Get key */
987 pobj2 = PM_FP->fo_func->f_co->co_names->val[t16];
989 /* Remove key,val pair from current frame's attrs dict */
990 retval = dict_delItem((pPmObj_t)PM_FP->fo_attrs, pobj2);
991 PM_BREAK_IF_ERROR(retval);
992 continue;
993 #endif /* HAVE_DEL */
995 case UNPACK_SEQUENCE:
996 /* Get ptr to sequence */
997 pobj1 = PM_POP();
999 #ifdef HAVE_BYTEARRAY
1000 /* If object is an instance, get the thing it contains */
1001 if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_CLI)
1003 retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj1)->cli_attrs,
1004 PM_NONE,
1005 &pobj2);
1006 PM_RETURN_IF_ERROR(retval);
1007 pobj1 = pobj2;
1009 #endif /* HAVE_BYTEARRAY */
1012 * Get the length of the sequence; this will
1013 * raise TypeError if obj is not a sequence.
1015 * #59: Unpacking to a Dict shall not be supported
1017 retval = seq_getLength(pobj1, &t16);
1018 if (retval != PM_RET_OK)
1020 GET_ARG();
1021 break;
1024 /* Raise ValueError if seq length does not match num args */
1025 if (t16 != GET_ARG())
1027 PM_RAISE(retval, PM_RET_EX_VAL);
1028 break;
1031 /* Push sequence's objs onto stack */
1032 for (; --t16 >= 0;)
1034 retval = seq_getSubscript(pobj1, t16, &pobj2);
1035 PM_BREAK_IF_ERROR(retval);
1036 PM_PUSH(pobj2);
1039 /* Test again outside the for loop */
1040 PM_BREAK_IF_ERROR(retval);
1041 continue;
1043 case FOR_ITER:
1044 t16 = GET_ARG();
1046 #ifdef HAVE_GENERATORS
1047 /* If TOS is an instance, call next method */
1048 if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
1050 /* Get the next() func */
1051 retval = class_getAttr(TOS, PM_NEXT_STR, &pobj1);
1052 PM_BREAK_IF_ERROR(retval);
1054 /* Push the func and instance as an arg */
1055 pobj2 = TOS;
1056 PM_PUSH(pobj1);
1057 PM_PUSH(pobj2);
1058 t16 = 1;
1060 /* Ensure pobj1 is the func */
1061 goto CALL_FUNC_FOR_ITER;
1063 else
1064 #endif /* HAVE_GENERATORS */
1066 /* Get the next item in the sequence iterator */
1067 retval = seqiter_getNext(TOS, &pobj2);
1070 /* Catch StopIteration early: pop iterator and break loop */
1071 if (retval == PM_RET_EX_STOP)
1073 PM_SP--;
1074 retval = PM_RET_OK;
1075 PM_IP += t16;
1076 continue;
1078 PM_BREAK_IF_ERROR(retval);
1080 /* Push the next item onto the stack */
1081 PM_PUSH(pobj2);
1082 continue;
1084 case STORE_ATTR:
1085 /* TOS.name = TOS1 */
1086 /* Get names index */
1087 t16 = GET_ARG();
1089 /* Get attrs dict from obj */
1090 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FXN)
1091 || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD))
1093 pobj2 = (pPmObj_t)((pPmFunc_t)TOS)->f_attrs;
1096 #ifdef HAVE_CLASSES
1097 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO)
1099 pobj2 = (pPmObj_t)((pPmClass_t)TOS)->cl_attrs;
1101 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
1103 pobj2 = (pPmObj_t)((pPmInstance_t)TOS)->cli_attrs;
1105 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MTH)
1107 pobj2 = (pPmObj_t)((pPmMethod_t)TOS)->m_attrs;
1109 #endif /* HAVE_CLASSES */
1111 /* Other types result in an AttributeError */
1112 else
1114 PM_RAISE(retval, PM_RET_EX_ATTR);
1115 break;
1118 /* If attrs is not a dict, raise SystemError */
1119 if (OBJ_GET_TYPE(pobj2) != OBJ_TYPE_DIC)
1121 PM_RAISE(retval, PM_RET_EX_SYS);
1122 break;
1125 /* Get name/key obj */
1126 pobj3 = PM_FP->fo_func->f_co->co_names->val[t16];
1128 /* Set key=val in obj's dict */
1129 retval = dict_setItem(pobj2, pobj3, TOS1);
1130 PM_BREAK_IF_ERROR(retval);
1131 PM_SP -= 2;
1132 continue;
1134 #ifdef HAVE_DEL
1135 case DELETE_ATTR:
1136 /* del TOS.name */
1137 /* Get names index */
1138 t16 = GET_ARG();
1140 /* Get attrs dict from obj */
1141 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FXN)
1142 || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD))
1144 pobj2 = (pPmObj_t)((pPmFunc_t)TOS)->f_attrs;
1147 #ifdef HAVE_CLASSES
1148 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO)
1150 pobj2 = (pPmObj_t)((pPmClass_t)TOS)->cl_attrs;
1152 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
1154 pobj2 = (pPmObj_t)((pPmInstance_t)TOS)->cli_attrs;
1156 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MTH)
1158 pobj2 = (pPmObj_t)((pPmMethod_t)TOS)->m_attrs;
1160 #endif /* HAVE_CLASSES */
1162 /* Other types result in an AttributeError */
1163 else
1165 PM_RAISE(retval, PM_RET_EX_ATTR);
1166 break;
1169 /* If attrs is not a dict, raise SystemError */
1170 if (OBJ_GET_TYPE(pobj2) != OBJ_TYPE_DIC)
1172 PM_RAISE(retval, PM_RET_EX_SYS);
1173 break;
1176 /* Get name/key obj */
1177 pobj3 = PM_FP->fo_func->f_co->co_names->val[t16];
1179 /* Remove key,val from obj's dict */
1180 retval = dict_delItem(pobj2, pobj3);
1182 /* Raise an AttributeError if key is not found */
1183 if (retval == PM_RET_EX_KEY)
1185 PM_RAISE(retval, PM_RET_EX_ATTR);
1188 PM_BREAK_IF_ERROR(retval);
1189 PM_SP--;
1190 continue;
1191 #endif /* HAVE_DEL */
1193 case STORE_GLOBAL:
1194 /* Get name index */
1195 t16 = GET_ARG();
1197 /* Get key */
1198 pobj2 = PM_FP->fo_func->f_co->co_names->val[t16];
1200 /* Set key=val in global dict */
1201 retval = dict_setItem((pPmObj_t)PM_FP->fo_globals, pobj2, TOS);
1202 PM_BREAK_IF_ERROR(retval);
1203 PM_SP--;
1204 continue;
1206 #ifdef HAVE_DEL
1207 case DELETE_GLOBAL:
1208 /* Get name index */
1209 t16 = GET_ARG();
1211 /* Get key */
1212 pobj2 = PM_FP->fo_func->f_co->co_names->val[t16];
1214 /* Remove key,val from globals */
1215 retval = dict_delItem((pPmObj_t)PM_FP->fo_globals, pobj2);
1216 PM_BREAK_IF_ERROR(retval);
1217 continue;
1218 #endif /* HAVE_DEL */
1220 case DUP_TOPX:
1221 t16 = GET_ARG();
1222 C_ASSERT(t16 <= 3);
1224 pobj1 = TOS;
1225 pobj2 = TOS1;
1226 pobj3 = TOS2;
1227 if (t16 >= 3)
1228 PM_PUSH(pobj3);
1229 if (t16 >= 2)
1230 PM_PUSH(pobj2);
1231 if (t16 >= 1)
1232 PM_PUSH(pobj1);
1233 continue;
1235 case LOAD_CONST:
1236 /* Get const's index in CO */
1237 t16 = GET_ARG();
1239 /* Push const on stack */
1240 PM_PUSH(PM_FP->fo_func->f_co->co_consts->val[t16]);
1241 continue;
1243 case LOAD_NAME:
1244 /* Get name index */
1245 t16 = GET_ARG();
1247 /* Get name from names tuple */
1248 pobj1 = PM_FP->fo_func->f_co->co_names->val[t16];
1250 /* Get value from frame's attrs dict */
1251 retval = dict_getItem((pPmObj_t)PM_FP->fo_attrs, pobj1, &pobj2);
1252 if (retval == PM_RET_EX_KEY)
1254 /* Get val from globals */
1255 retval = dict_getItem((pPmObj_t)PM_FP->fo_globals,
1256 pobj1, &pobj2);
1258 /* Check for name in the builtins module if it is loaded */
1259 if ((retval == PM_RET_EX_KEY) && (PM_PBUILTINS != C_NULL))
1261 /* Get val from builtins */
1262 retval = dict_getItem(PM_PBUILTINS, pobj1, &pobj2);
1263 if (retval == PM_RET_EX_KEY)
1265 /* Name not defined, raise NameError */
1266 PM_RAISE(retval, PM_RET_EX_NAME);
1267 break;
1271 PM_BREAK_IF_ERROR(retval);
1272 PM_PUSH(pobj2);
1273 continue;
1275 case BUILD_TUPLE:
1276 /* Get num items */
1277 t16 = GET_ARG();
1278 retval = tuple_new(t16, &pobj1);
1279 PM_BREAK_IF_ERROR(retval);
1281 /* Fill tuple with ptrs to objs */
1282 for (; --t16 >= 0;)
1284 ((pPmTuple_t)pobj1)->val[t16] = PM_POP();
1286 PM_PUSH(pobj1);
1287 continue;
1289 case BUILD_LIST:
1290 t16 = GET_ARG();
1291 retval = list_new(&pobj1);
1292 PM_BREAK_IF_ERROR(retval);
1293 for (; --t16 >= 0;)
1295 /* Insert obj into list */
1296 heap_gcPushTempRoot(pobj1, &objid);
1297 retval = list_insert(pobj1, 0, TOS);
1298 heap_gcPopTempRoot(objid);
1299 PM_BREAK_IF_ERROR(retval);
1300 PM_SP--;
1302 /* Test again outside for loop */
1303 PM_BREAK_IF_ERROR(retval);
1305 /* push list onto stack */
1306 PM_PUSH(pobj1);
1307 continue;
1309 case BUILD_MAP:
1310 /* Argument is ignored */
1311 t16 = GET_ARG();
1312 retval = dict_new(&pobj1);
1313 PM_BREAK_IF_ERROR(retval);
1314 PM_PUSH(pobj1);
1315 continue;
1317 case LOAD_ATTR:
1318 /* Implements TOS.attr */
1319 t16 = GET_ARG();
1321 /* Get attrs dict from obj */
1322 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FXN) ||
1323 (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD))
1325 pobj1 = (pPmObj_t)((pPmFunc_t)TOS)->f_attrs;
1328 #ifdef HAVE_CLASSES
1329 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO)
1331 pobj1 = (pPmObj_t)((pPmClass_t)TOS)->cl_attrs;
1333 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
1335 pobj1 = (pPmObj_t)((pPmInstance_t)TOS)->cli_attrs;
1337 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MTH)
1339 pobj1 = (pPmObj_t)((pPmMethod_t)TOS)->m_attrs;
1341 #endif /* HAVE_CLASSES */
1343 /* Other types result in an AttributeError */
1344 else
1346 PM_RAISE(retval, PM_RET_EX_ATTR);
1347 break;
1350 /* If attrs is not a dict, raise SystemError */
1351 if (OBJ_GET_TYPE(pobj1) != OBJ_TYPE_DIC)
1353 PM_RAISE(retval, PM_RET_EX_SYS);
1354 break;
1357 /* Get name */
1358 pobj2 = PM_FP->fo_func->f_co->co_names->val[t16];
1360 /* Get attr with given name */
1361 retval = dict_getItem(pobj1, pobj2, &pobj3);
1363 #ifdef HAVE_CLASSES
1365 * If attr is not found and object is a class or instance,
1366 * try to get the attribute from the class attrs or parent(s)
1368 if ((retval == PM_RET_EX_KEY) &&
1369 ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO)
1370 || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)))
1372 retval = class_getAttr(TOS, pobj2, &pobj3);
1374 #endif /* HAVE_CLASSES */
1376 /* Raise an AttributeError if key is not found */
1377 if (retval == PM_RET_EX_KEY)
1379 PM_RAISE(retval, PM_RET_EX_ATTR);
1381 PM_BREAK_IF_ERROR(retval);
1383 #ifdef HAVE_CLASSES
1384 /* If obj is an instance and attr is a func, create method */
1385 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI) &&
1386 (OBJ_GET_TYPE(pobj3) == OBJ_TYPE_FXN))
1388 pobj2 = pobj3;
1389 retval = class_method(TOS, pobj2, &pobj3);
1390 PM_BREAK_IF_ERROR(retval);
1392 #endif /* HAVE_CLASSES */
1394 /* Put attr on the stack */
1395 TOS = pobj3;
1396 continue;
1398 case COMPARE_OP:
1399 retval = PM_RET_OK;
1400 t16 = GET_ARG();
1402 #ifdef HAVE_FLOAT
1403 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
1404 || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
1406 retval = float_compare(TOS1, TOS, &pobj3, (PmCompare_t)t16);
1407 PM_SP--;
1408 TOS = pobj3;
1409 continue;
1411 #endif /* HAVE_FLOAT */
1413 /* Handle all integer-to-integer (or bool) comparisons */
1414 if (((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
1415 || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_BOOL))
1416 && ((OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT)
1417 || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_BOOL)))
1419 int32_t a = ((pPmInt_t)TOS1)->val;
1420 int32_t b = ((pPmInt_t)TOS)->val;
1422 switch (t16)
1424 /* *INDENT-OFF* */
1425 case COMP_LT: t8 = (int8_t)(a < b); break;
1426 case COMP_LE: t8 = (int8_t)(a <= b); break;
1427 case COMP_EQ: t8 = (int8_t)(a == b); break;
1428 case COMP_NE: t8 = (int8_t)(a != b); break;
1429 case COMP_GT: t8 = (int8_t)(a > b); break;
1430 case COMP_GE: t8 = (int8_t)(a >= b); break;
1431 case COMP_IS: t8 = (int8_t)(TOS == TOS1); break;
1432 case COMP_IS_NOT: t8 = (int8_t)(TOS != TOS1);break;
1433 case COMP_IN:
1434 case COMP_NOT_IN:
1435 PM_RAISE(retval, PM_RET_EX_TYPE);
1436 break;
1438 default:
1439 /* Other compares are not yet supported */
1440 PM_RAISE(retval, PM_RET_EX_SYS);
1441 break;
1442 /* *INDENT-ON* */
1444 PM_BREAK_IF_ERROR(retval);
1445 pobj3 = (t8) ? PM_TRUE : PM_FALSE;
1448 /* Handle non-integer comparisons */
1449 else
1451 retval = PM_RET_OK;
1452 switch (t16)
1454 case COMP_EQ:
1455 case COMP_NE:
1456 /* Handle equality for non-int types */
1457 pobj3 = PM_FALSE;
1458 t8 = obj_compare(TOS, TOS1);
1459 if (((t8 == C_SAME) && (t16 == COMP_EQ))
1460 || ((t8 == C_DIFFER) && (t16 == COMP_NE)))
1462 pobj3 = PM_TRUE;
1464 break;
1466 case COMP_IN:
1467 case COMP_NOT_IN:
1468 /* Handle membership comparisons */
1469 pobj3 = PM_FALSE;
1470 retval = obj_isIn(TOS, TOS1);
1471 if (retval == PM_RET_OK)
1473 if (t16 == COMP_IN)
1475 pobj3 = PM_TRUE;
1478 else if (retval == PM_RET_NO)
1480 retval = PM_RET_OK;
1481 if (t16 == COMP_NOT_IN)
1483 pobj3 = PM_TRUE;
1486 break;
1488 default:
1489 /* Other comparisons are not implemented */
1490 PM_RAISE(retval, PM_RET_EX_SYS);
1491 break;
1493 PM_BREAK_IF_ERROR(retval);
1495 PM_SP--;
1496 TOS = pobj3;
1497 continue;
1499 case IMPORT_NAME:
1500 /* Get name index */
1501 t16 = GET_ARG();
1503 /* Get name String obj */
1504 pobj1 = PM_FP->fo_func->f_co->co_names->val[t16];
1506 /* Pop unused None object */
1507 PM_SP--;
1509 /* Ensure "level" is -1; no support for relative import yet */
1510 C_ASSERT(obj_compare(TOS, PM_NEGONE) == C_SAME);
1512 /* #110: Prevent importing previously-loaded module */
1513 /* If the named module is in globals, put it on the stack */
1514 retval =
1515 dict_getItem((pPmObj_t)PM_FP->fo_globals, pobj1, &pobj2);
1516 if ((retval == PM_RET_OK)
1517 && (OBJ_GET_TYPE(pobj2) == OBJ_TYPE_MOD))
1519 TOS = pobj2;
1520 continue;
1523 /* Load module from image */
1524 retval = mod_import(pobj1, &pobj2);
1525 PM_BREAK_IF_ERROR(retval);
1527 /* Put Module on top of stack */
1528 TOS = pobj2;
1530 /* Code after here is a duplicate of CALL_FUNCTION */
1531 /* Make frame object to interpret the module's root code */
1532 heap_gcPushTempRoot(pobj2, &objid);
1533 retval = frame_new(pobj2, &pobj3);
1534 heap_gcPopTempRoot(objid);
1535 PM_BREAK_IF_ERROR(retval);
1537 /* No arguments to pass */
1539 /* Keep ref to current frame */
1540 ((pPmFrame_t)pobj3)->fo_back = PM_FP;
1542 /* Handle to have None popped on return */
1543 ((pPmFrame_t)pobj3)->fo_isImport = (uint8_t)1;
1545 /* Set new frame */
1546 PM_FP = (pPmFrame_t)pobj3;
1547 continue;
1549 #ifdef HAVE_IMPORTS
1550 case IMPORT_FROM:
1551 /* #102: Implement the remaining IMPORT_ bytecodes */
1552 /* Expect the module on the top of the stack */
1553 C_ASSERT(OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD);
1554 pobj1 = TOS;
1556 /* Get the name of the object to import */
1557 t16 = GET_ARG();
1558 pobj2 = PM_FP->fo_func->f_co->co_names->val[t16];
1560 /* Get the object from the module's attributes */
1561 retval = dict_getItem((pPmObj_t)((pPmFunc_t)pobj1)->f_attrs,
1562 pobj2, &pobj3);
1563 PM_BREAK_IF_ERROR(retval);
1565 /* Push the object onto the top of the stack */
1566 PM_PUSH(pobj3);
1567 continue;
1568 #endif /* HAVE_IMPORTS */
1570 case JUMP_FORWARD:
1571 t16 = GET_ARG();
1572 PM_IP += t16;
1573 continue;
1575 case JUMP_IF_FALSE:
1576 t16 = GET_ARG();
1577 if (obj_isFalse(TOS))
1579 PM_IP += t16;
1581 continue;
1583 case JUMP_IF_TRUE:
1584 t16 = GET_ARG();
1585 if (!obj_isFalse(TOS))
1587 PM_IP += t16;
1589 continue;
1591 case JUMP_ABSOLUTE:
1592 case CONTINUE_LOOP:
1593 /* Get target offset (bytes) */
1594 t16 = GET_ARG();
1596 /* Jump to base_ip + arg */
1597 PM_IP = PM_FP->fo_func->f_co->co_codeaddr + t16;
1598 continue;
1600 case LOAD_GLOBAL:
1601 /* Get name */
1602 t16 = GET_ARG();
1603 pobj1 = PM_FP->fo_func->f_co->co_names->val[t16];
1605 /* Try globals first */
1606 retval = dict_getItem((pPmObj_t)PM_FP->fo_globals,
1607 pobj1, &pobj2);
1609 /* If that didn't work, try builtins */
1610 if (retval == PM_RET_EX_KEY)
1612 retval = dict_getItem(PM_PBUILTINS, pobj1, &pobj2);
1614 /* No such global, raise NameError */
1615 if (retval == PM_RET_EX_KEY)
1617 PM_RAISE(retval, PM_RET_EX_NAME);
1618 break;
1621 PM_BREAK_IF_ERROR(retval);
1622 PM_PUSH(pobj2);
1623 continue;
1625 case SETUP_LOOP:
1627 uint8_t *pchunk;
1629 /* Get block span (bytes) */
1630 t16 = GET_ARG();
1632 /* Create block */
1633 retval = heap_getChunk(sizeof(PmBlock_t), &pchunk);
1634 PM_BREAK_IF_ERROR(retval);
1635 pobj1 = (pPmObj_t)pchunk;
1636 OBJ_SET_TYPE(pobj1, OBJ_TYPE_BLK);
1638 /* Store current stack pointer */
1639 ((pPmBlock_t)pobj1)->b_sp = PM_SP;
1641 /* Default handler is to exit block/loop */
1642 ((pPmBlock_t)pobj1)->b_handler = PM_IP + t16;
1643 ((pPmBlock_t)pobj1)->b_type = B_LOOP;
1645 /* Insert block into blockstack */
1646 ((pPmBlock_t)pobj1)->next = PM_FP->fo_blockstack;
1647 PM_FP->fo_blockstack = (pPmBlock_t)pobj1;
1648 continue;
1651 case LOAD_FAST:
1652 t16 = GET_ARG();
1653 PM_PUSH(PM_FP->fo_locals[t16]);
1654 continue;
1656 case STORE_FAST:
1657 t16 = GET_ARG();
1658 PM_FP->fo_locals[t16] = PM_POP();
1659 continue;
1661 #ifdef HAVE_DEL
1662 case DELETE_FAST:
1663 t16 = GET_ARG();
1664 PM_FP->fo_locals[t16] = PM_NONE;
1665 continue;
1666 #endif /* HAVE_DEL */
1668 #ifdef HAVE_ASSERT
1669 case RAISE_VARARGS:
1670 t16 = GET_ARG();
1672 /* Only supports taking 1 arg for now */
1673 if (t16 != 1)
1675 PM_RAISE(retval, PM_RET_EX_SYS);
1676 break;
1679 /* Load Exception class from builtins */
1680 retval = dict_getItem(PM_PBUILTINS, PM_EXCEPTION_STR, &pobj2);
1681 if (retval != PM_RET_OK)
1683 PM_RAISE(retval, PM_RET_EX_SYS);
1684 break;
1687 /* Raise TypeError if TOS is not an instance of Exception */
1688 pobj1 = TOS;
1689 if ((OBJ_GET_TYPE(pobj1) != OBJ_TYPE_CLO)
1690 || !class_isSubclass(pobj1, pobj2))
1692 PM_RAISE(retval, PM_RET_EX_TYPE);
1693 break;
1696 /* Push the traceback, parameter and exception object */
1697 TOS = PM_NONE;
1698 PM_PUSH(PM_NONE);
1699 PM_PUSH(pobj1);
1701 /* Get the exception's code attr */
1702 retval = dict_getItem((pPmObj_t)((pPmClass_t)pobj1)->cl_attrs,
1703 PM_CODE_STR, &pobj2);
1704 PM_BREAK_IF_ERROR(retval);
1706 /* Raise exception by breaking with retval set to code */
1707 PM_RAISE(retval, (PmReturn_t)(((pPmInt_t)pobj2)->val & 0xFF));
1708 break;
1709 #endif /* HAVE_ASSERT */
1711 case CALL_FUNCTION:
1712 /* Get num args */
1713 t16 = GET_ARG();
1715 /* Ensure no keyword args */
1716 if ((t16 & (uint16_t)0xFF00) != 0)
1718 PM_RAISE(retval, PM_RET_EX_SYS);
1719 break;
1722 /* Get the callable */
1723 pobj1 = STACK(t16);
1725 /* Useless push to get temp-roots stack level used in cleanup */
1726 heap_gcPushTempRoot(pobj1, &objid);
1728 C_DEBUG_PRINT(VERBOSITY_LOW,
1729 "interpret(), CALL_FUNCTION on <obj type=%d @ %p>\n",
1730 OBJ_GET_TYPE(pobj1), pobj1);
1732 #ifdef HAVE_GENERATORS
1733 /* If the callable is a generator function (can't be native) */
1734 if ((OBJ_GET_TYPE(pobj1) == OBJ_TYPE_FXN)
1735 && (OBJ_GET_TYPE(((pPmFunc_t)pobj1)->f_co) == OBJ_TYPE_COB)
1736 && (((pPmFunc_t)pobj1)->f_co->co_flags & CO_GENERATOR))
1738 #ifdef HAVE_DEFAULTARGS
1739 /* Num required args := argcount - num default args */
1740 t8 = ((pPmFunc_t)pobj1)->f_co->co_argcount;
1741 if (((pPmFunc_t)pobj1)->f_defaultargs != C_NULL)
1743 t8 -= ((pPmTuple_t)((pPmFunc_t)pobj1)->f_defaultargs)->
1744 length;
1748 * Raise a TypeError if num args passed
1749 * is more than allowed or less than required
1751 if (((t16 & ((uint8_t)0xFF))
1752 > ((pPmFunc_t)pobj1)->f_co->co_argcount)
1753 || ((t16 & ((uint8_t)0xFF)) < t8))
1754 #else
1755 if ((t16 & ((uint8_t)0xFF)) !=
1756 ((pPmFunc_t)pobj1)->f_co->co_argcount)
1757 #endif /* HAVE_DEFAULTARGS */
1759 PM_RAISE(retval, PM_RET_EX_TYPE);
1760 break;
1763 /* Collect the function and arguments into a tuple */
1764 retval = tuple_new(t16 + 1, &pobj2);
1765 heap_gcPushTempRoot(pobj2, &objid2);
1766 PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP);
1767 sli_memcpy((uint8_t *)&((pPmTuple_t)pobj2)->val,
1768 (uint8_t *)&STACK(t16),
1769 (t16 + 1) * sizeof(pPmObj_t));
1771 /* Remove old args, push func/args tuple as one arg */
1772 PM_SP -= t16;
1773 PM_PUSH(pobj2);
1774 t16 = 1;
1776 /* Set pobj1 and stack to create an instance of Generator */
1777 retval = dict_getItem(PM_PBUILTINS, PM_GENERATOR_STR,
1778 &pobj1);
1779 C_ASSERT(retval == PM_RET_OK);
1780 STACK(t16) = pobj1;
1782 #endif /* HAVE_GENERATORS */
1784 #ifdef HAVE_CLASSES
1785 /* If the callable is a class, create an instance of it */
1786 if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_CLO)
1788 /* This marks that the original callable was a class */
1789 bc = 0;
1791 /* Replace class with new instance */
1792 retval = class_instantiate(pobj1, &pobj2);
1793 heap_gcPushTempRoot(pobj2, &objid2);
1794 STACK(t16) = pobj2;
1796 /* If __init__ does not exist */
1797 pobj3 = C_NULL;
1798 retval = class_getAttr(pobj1, PM_INIT_STR, &pobj3);
1799 if (retval == PM_RET_EX_KEY)
1801 /* Raise TypeError if there are args */
1802 if (t16 > 0)
1804 PM_RAISE(retval, PM_RET_EX_TYPE);
1805 goto CALL_FUNC_CLEANUP;
1808 /* Otherwise, continue with instance */
1809 heap_gcPopTempRoot(objid);
1810 continue;
1812 else if (retval != PM_RET_OK)
1814 PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP);
1817 /* Slide the arguments up 1 slot in the stack */
1818 PM_SP++;
1819 for (t8 = 0; t8 < t16; t8++)
1821 STACK(t8) = STACK(t8 + 1);
1824 /* Convert __init__ to method, insert it as the callable */
1825 retval = class_method(pobj2, pobj3, &pobj1);
1826 PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP);
1827 heap_gcPushTempRoot(pobj2, &objid2);
1828 STACK(t16) = pobj1;
1829 /* Fall through to call the method */
1832 if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_MTH)
1834 /* Set the method's func to be the callable */
1835 STACK(t16) = (pPmObj_t)((pPmMethod_t)pobj1)->m_func;
1837 /* Slide the arguments up 1 slot in the stack */
1838 PM_SP++;
1839 for (t8 = 0; t8 < t16; t8++)
1841 STACK(t8) = STACK(t8 + 1);
1844 /* Insert instance as "self" arg to the method */
1845 STACK(t16++) = (pPmObj_t)((pPmMethod_t)pobj1)->m_instance;
1847 /* Refresh the callable */
1848 pobj1 = (pPmObj_t)((pPmMethod_t)pobj1)->m_func;
1850 #endif /* HAVE_CLASSES */
1852 #ifdef HAVE_GENERATORS
1853 CALL_FUNC_FOR_ITER:
1854 #endif /* HAVE_GENERATORS */
1855 /* Raise a TypeError if object is not callable */
1856 if (OBJ_GET_TYPE(pobj1) != OBJ_TYPE_FXN)
1858 PM_RAISE(retval, PM_RET_EX_TYPE);
1859 goto CALL_FUNC_CLEANUP;
1862 /* If it is a regular func (not native) */
1863 if (OBJ_GET_TYPE(((pPmFunc_t)pobj1)->f_co) == OBJ_TYPE_COB)
1866 * #132 Raise TypeError if num args does not match the
1867 * code object's expected argcount
1870 #ifdef HAVE_DEFAULTARGS
1871 /* Num required args := argcount - num default args */
1872 t8 = ((pPmFunc_t)pobj1)->f_co->co_argcount;
1873 if (((pPmFunc_t)pobj1)->f_defaultargs != C_NULL)
1875 t8 -= ((pPmTuple_t)((pPmFunc_t)pobj1)->f_defaultargs)->
1876 length;
1880 * Raise a TypeError if num args passed
1881 * is more than allowed or less than required
1883 if (((t16 & ((uint8_t)0xFF))
1884 > ((pPmFunc_t)pobj1)->f_co->co_argcount)
1885 || ((t16 & ((uint8_t)0xFF)) < t8))
1886 #else
1887 if ((t16 & ((uint8_t)0xFF)) !=
1888 ((pPmFunc_t)pobj1)->f_co->co_argcount)
1889 #endif /* HAVE_DEFAULTARGS */
1891 PM_RAISE(retval, PM_RET_EX_TYPE);
1892 break;
1895 /* Make frame object to run the func object */
1896 retval = frame_new(pobj1, &pobj2);
1897 heap_gcPushTempRoot(pobj2, &objid2);
1898 PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP);
1900 #ifdef HAVE_CLASSES
1902 * If the original callable was a class, indicate that
1903 * the frame is running the initializer so that
1904 * its return object is checked for None and ignored.
1906 if (bc == 0)
1908 ((pPmFrame_t)pobj2)->fo_isInit = C_TRUE;
1910 #endif /* HAVE_CLASSES */
1912 #ifdef HAVE_DEFAULTARGS
1913 /* If this func has default arguments, put them in place */
1914 if (((pPmFunc_t)pobj1)->f_defaultargs != C_NULL)
1916 int8_t i = 0;
1918 /* Copy default args into the new frame's locals */
1919 for ( /* t8 set above */ ;
1920 t8 < ((pPmFunc_t)pobj1)->f_co->co_argcount; t8++)
1922 ((pPmFrame_t)pobj2)->fo_locals[t8] =
1923 ((pPmTuple_t)((pPmFunc_t)pobj1)->
1924 f_defaultargs)->val[i++];
1927 #endif /* HAVE_DEFAULTARGS */
1929 /* Pass args to new frame */
1930 while (--t16 >= 0)
1933 * Pop args from stack right to left,
1934 * since args are pushed left to right,
1936 ((pPmFrame_t)pobj2)->fo_locals[t16] = PM_POP();
1939 #ifdef HAVE_CLOSURES
1940 /* #256: Add support for closures */
1941 /* Copy arguments that become cellvars */
1942 if (((pPmFunc_t)pobj1)->f_co->co_cellvars != C_NULL)
1944 for (t8 = 0;
1945 t8 < ((pPmFunc_t)pobj1)->f_co->co_cellvars->length;
1946 t8++)
1948 if (((pPmInt_t)((pPmFunc_t)pobj1)->
1949 f_co->co_cellvars->val[t8])->val >= 0)
1951 ((pPmFrame_t)pobj2)->fo_locals[
1952 ((pPmFunc_t)pobj1)->f_co->co_nlocals + t8] =
1953 ((pPmFrame_t)pobj2)->fo_locals[
1954 ((pPmInt_t)(((pPmFunc_t)pobj1)->
1955 f_co->co_cellvars->val[t8]))->val
1961 /* Fill frame's freevars with references from closure */
1962 for (t8 = 0;
1963 t8 < ((pPmFunc_t)pobj1)->f_co->co_nfreevars;
1964 t8++)
1966 C_ASSERT(((pPmFunc_t)pobj1)->f_closure != C_NULL);
1967 ((pPmFrame_t)pobj2)->fo_locals[
1968 ((pPmFunc_t)pobj1)->f_co->co_nlocals
1969 + ((((pPmFunc_t)pobj1)->f_co->co_cellvars == C_NULL) ? 0 : ((pPmFunc_t)pobj1)->f_co->co_cellvars->length)
1970 + t8] = ((pPmFunc_t)pobj1)->f_closure->val[t8];
1972 #endif /* HAVE_CLOSURES */
1974 /* Pop func obj */
1975 pobj3 = PM_POP();
1977 /* Keep ref to current frame */
1978 ((pPmFrame_t)pobj2)->fo_back = PM_FP;
1980 /* Set new frame */
1981 PM_FP = (pPmFrame_t)pobj2;
1984 /* If it's native func */
1985 else if (OBJ_GET_TYPE(((pPmFunc_t)pobj1)->f_co) ==
1986 OBJ_TYPE_NOB)
1988 /* Set number of locals (arguments) */
1989 gVmGlobal.nativeframe.nf_numlocals = (uint8_t)t16;
1991 /* Pop args from stack */
1992 while (--t16 >= 0)
1994 gVmGlobal.nativeframe.nf_locals[t16] = PM_POP();
1997 #ifdef HAVE_GC
1998 /* If the heap is low on memory, run the GC */
1999 if (heap_getAvail() < HEAP_GC_NF_THRESHOLD)
2001 retval = heap_gcRun();
2002 PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP);
2004 #endif /* HAVE_GC */
2006 /* Pop the function object */
2007 PM_SP--;
2009 /* Get native function index */
2010 pobj2 = (pPmObj_t)((pPmFunc_t)pobj1)->f_co;
2011 t16 = ((pPmNo_t)pobj2)->no_funcindx;
2013 /* Set flag, so the GC knows a native session is active */
2014 gVmGlobal.nativeframe.nf_active = C_TRUE;
2017 * CALL NATIVE FXN: pass caller's frame and numargs
2019 /* Positive index is a stdlib func */
2020 if (t16 >= 0)
2022 retval = std_nat_fxn_table[t16] (&PM_FP);
2025 /* Negative index is a usrlib func */
2026 else
2028 retval = usr_nat_fxn_table[-t16] (&PM_FP);
2032 * RETURN FROM NATIVE FXN
2035 /* Clear flag, so frame will not be marked by the GC */
2036 gVmGlobal.nativeframe.nf_active = C_FALSE;
2038 #ifdef HAVE_CLASSES
2039 /* If class's __init__ called, do not push a return obj */
2040 if (bc == 0)
2042 /* Raise TypeError if returned obj was not None */
2043 if ((retval == PM_RET_OK)
2044 && (gVmGlobal.nativeframe.nf_stack != PM_NONE))
2046 PM_RAISE(retval, PM_RET_EX_TYPE);
2047 goto CALL_FUNC_CLEANUP;
2050 else
2051 #endif /* HAVE_CLASSES */
2053 /* If the frame pointer was switched, do nothing to TOS */
2054 if (retval == PM_RET_FRAME_SWITCH)
2056 retval = PM_RET_OK;
2059 /* Otherwise, return the result from the native function */
2060 else
2062 PM_PUSH(gVmGlobal.nativeframe.nf_stack);
2065 CALL_FUNC_CLEANUP:
2066 heap_gcPopTempRoot(objid);
2067 PM_BREAK_IF_ERROR(retval);
2068 continue;
2070 case MAKE_FUNCTION:
2071 /* Get num default args to fxn */
2072 t16 = GET_ARG();
2075 * The current frame's globals become the function object's
2076 * globals. The current frame is the container object
2077 * of this new function object
2079 retval = func_new(TOS, (pPmObj_t)PM_FP->fo_globals, &pobj2);
2080 PM_BREAK_IF_ERROR(retval);
2082 /* Put any default args in a tuple */
2083 if (t16 > 0)
2086 #ifdef HAVE_DEFAULTARGS
2087 heap_gcPushTempRoot(pobj2, &objid);
2088 retval = tuple_new(t16, &pobj3);
2089 heap_gcPopTempRoot(objid);
2090 PM_BREAK_IF_ERROR(retval);
2091 PM_SP--;
2092 while (--t16 >= 0)
2094 ((pPmTuple_t)pobj3)->val[t16] = PM_POP();
2097 /* Set func's default args */
2098 ((pPmFunc_t)pobj2)->f_defaultargs = (pPmTuple_t)pobj3;
2099 #else
2100 /* Default arguments not configured in pmfeatures.h */
2101 PM_RAISE(retval, PM_RET_EX_SYS);
2102 break;
2103 #endif /* HAVE_DEFAULTARGS */
2106 else
2108 PM_SP--;
2111 /* Push func obj */
2112 PM_PUSH(pobj2);
2113 continue;
2115 #ifdef HAVE_CLOSURES
2116 case MAKE_CLOSURE:
2117 /* Get number of default args */
2118 t16 = GET_ARG();
2119 retval = func_new(TOS, (pPmObj_t)PM_FP->fo_globals, &pobj2);
2120 PM_BREAK_IF_ERROR(retval);
2122 /* Set closure of the new function */
2123 ((pPmFunc_t)pobj2)->f_closure = (pPmTuple_t)TOS1;
2124 PM_SP -= 2;
2126 /* Collect any default arguments into tuple */
2127 if (t16 > 0)
2129 heap_gcPushTempRoot(pobj2, &objid);
2130 retval = tuple_new(t16, &pobj3);
2131 heap_gcPopTempRoot(objid);
2132 PM_BREAK_IF_ERROR(retval);
2134 while (--t16 >= 0)
2136 ((pPmTuple_t)pobj3)->val[t16] = PM_POP();
2138 ((pPmFunc_t)pobj2)->f_defaultargs = (pPmTuple_t)pobj3;
2141 /* Push new func with closure */
2142 PM_PUSH(pobj2);
2143 continue;
2145 case LOAD_CLOSURE:
2146 case LOAD_DEREF:
2147 /* Loads the i'th cell of free variable storage onto TOS */
2148 t16 = GET_ARG();
2149 pobj1 = PM_FP->fo_locals[PM_FP->fo_func->f_co->co_nlocals + t16];
2150 if (pobj1 == C_NULL)
2152 PM_RAISE(retval, PM_RET_EX_SYS);
2153 break;
2155 PM_PUSH(pobj1);
2156 continue;
2158 case STORE_DEREF:
2159 /* Stores TOS into the i'th cell of free variable storage */
2160 t16 = GET_ARG();
2161 PM_FP->fo_locals[PM_FP->fo_func->f_co->co_nlocals + t16] = PM_POP();
2162 continue;
2163 #endif /* HAVE_CLOSURES */
2166 default:
2167 /* SystemError, unknown or unimplemented opcode */
2168 PM_RAISE(retval, PM_RET_EX_SYS);
2169 break;
2172 #ifdef HAVE_GENERATORS
2173 /* If got a StopIteration exception, check for a B_LOOP block */
2174 if (retval == PM_RET_EX_STOP)
2176 pobj1 = (pPmObj_t)PM_FP;
2177 while ((retval == PM_RET_EX_STOP) && (pobj1 != C_NULL))
2179 pobj2 = (pPmObj_t)((pPmFrame_t)pobj1)->fo_blockstack;
2180 while ((retval == PM_RET_EX_STOP) && (pobj2 != C_NULL))
2182 if (((pPmBlock_t)pobj2)->b_type == B_LOOP)
2184 /* Resume execution where the block handler says */
2185 /* Set PM_FP first, so PM_SP and PM_IP are set in the frame */
2186 PM_FP = (pPmFrame_t)pobj1;
2187 PM_SP = ((pPmBlock_t)pobj2)->b_sp;
2188 PM_IP = ((pPmBlock_t)pobj2)->b_handler;
2189 ((pPmFrame_t)pobj1)->fo_blockstack =
2190 ((pPmFrame_t)pobj1)->fo_blockstack->next;
2191 retval = PM_RET_OK;
2192 break;
2195 pobj2 = (pPmObj_t)((pPmBlock_t)pobj2)->next;
2197 pobj1 = (pPmObj_t)((pPmFrame_t)pobj1)->fo_back;
2199 if (retval == PM_RET_OK)
2201 continue;
2204 #endif /* HAVE_GENERATORS */
2207 * If execution reaches this point, it is because
2208 * a return value (from above) is not OK or we should exit the thread
2209 * (return of the function). In any case, remove the
2210 * current thread and reschedule.
2212 PM_REPORT_IF_ERROR(retval);
2214 /* If this is the last thread, return the error code */
2215 if ((gVmGlobal.threadList->length <= 1) && (retval != PM_RET_OK))
2217 break;
2220 retval = list_remove((pPmObj_t)gVmGlobal.threadList,
2221 (pPmObj_t)gVmGlobal.pthread);
2222 gVmGlobal.pthread = C_NULL;
2223 PM_BREAK_IF_ERROR(retval);
2225 retval = interp_reschedule();
2226 PM_BREAK_IF_ERROR(retval);
2229 return retval;
2233 PmReturn_t
2234 interp_reschedule(void)
2236 PmReturn_t retval = PM_RET_OK;
2237 static uint8_t threadIndex = (uint8_t)0;
2238 pPmObj_t pobj;
2240 /* If there are no threads in the runnable list, null the active thread */
2241 if (gVmGlobal.threadList->length == 0)
2243 gVmGlobal.pthread = C_NULL;
2246 /* Otherwise, get the next thread in the list (round robin) */
2247 else
2249 if (++threadIndex >= gVmGlobal.threadList->length)
2251 threadIndex = (uint8_t)0;
2253 retval = list_getItem((pPmObj_t)gVmGlobal.threadList, threadIndex,
2254 &pobj);
2255 gVmGlobal.pthread = (pPmThread_t)pobj;
2256 PM_RETURN_IF_ERROR(retval);
2259 /* Clear flag to indicate a reschedule has occurred */
2260 interp_setRescheduleFlag(0);
2261 return retval;
2265 PmReturn_t
2266 interp_addThread(pPmFunc_t pfunc)
2268 PmReturn_t retval;
2269 pPmObj_t pframe;
2270 pPmObj_t pthread;
2271 uint8_t objid1, objid2;
2273 /* Create a frame for the func */
2274 retval = frame_new((pPmObj_t)pfunc, &pframe);
2275 PM_RETURN_IF_ERROR(retval);
2277 /* Create a thread with this new frame */
2278 heap_gcPushTempRoot(pframe, &objid1);
2279 retval = thread_new(pframe, &pthread);
2280 if (retval != PM_RET_OK)
2282 heap_gcPopTempRoot(objid1);
2283 return retval;
2286 /* Add thread to end of list */
2287 heap_gcPushTempRoot(pthread, &objid2);
2288 retval = list_append((pPmObj_t)gVmGlobal.threadList, pthread);
2289 heap_gcPopTempRoot(objid1);
2290 return retval;
2294 void
2295 interp_setRescheduleFlag(uint8_t boolean)
2297 gVmGlobal.reschedule = boolean;