python-on-a-chip online compiler

Dependencies:   mbed TSI

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers interp.c Source File

interp.c

Go to the documentation of this file.
00001 /*
00002 # This file is Copyright 2002 Dean Hall.
00003 # This file is part of the PyMite VM.
00004 # This file is licensed under the MIT License.
00005 # See the LICENSE file for details.
00006 */
00007 
00008 
00009 #undef __FILE_ID__
00010 #define __FILE_ID__ 0x09
00011 
00012 
00013 /**
00014  * \file
00015  * \brief VM Interpreter
00016  *
00017  * VM interpreter operations.
00018  */
00019 
00020 
00021 #include "pm.h"
00022 
00023 
00024 PmReturn_t
00025 interpret(const uint8_t returnOnNoThreads)
00026 {
00027     PmReturn_t retval = PM_RET_OK;
00028     pPmObj_t pobj1 = C_NULL;
00029     pPmObj_t pobj2 = C_NULL;
00030     pPmObj_t pobj3 = C_NULL;
00031     int16_t t16 = 0;
00032     int8_t t8 = 0;
00033     uint8_t bc;
00034     uint8_t objid, objid2;
00035 
00036     /* Activate a thread the first time */
00037     retval = interp_reschedule();
00038     PM_RETURN_IF_ERROR(retval);
00039 
00040     /* Interpret loop */
00041     for (;;)
00042     {
00043         if (gVmGlobal.pthread == C_NULL)
00044         {
00045             if (returnOnNoThreads)
00046             {
00047                 /* User chose to return on no threads left */
00048                 return retval;
00049             }
00050 
00051             /*
00052              * Without a frame there is nothing to execute, so reschedule
00053              * (possibly activating a recently added thread).
00054              */
00055             retval = interp_reschedule();
00056             PM_BREAK_IF_ERROR(retval);
00057             continue;
00058         }
00059 
00060         /* Reschedule threads if flag is true? */
00061         if (gVmGlobal.reschedule)
00062         {
00063             retval = interp_reschedule();
00064             PM_BREAK_IF_ERROR(retval);
00065         }
00066 
00067         /* Get byte; the func post-incrs PM_IP */
00068         bc = mem_getByte(PM_FP->fo_memspace, &PM_IP);
00069         switch (bc)
00070         {
00071             case POP_TOP:
00072                 pobj1 = PM_POP();
00073                 continue;
00074 
00075             case ROT_TWO:
00076                 pobj1 = TOS;
00077                 TOS = TOS1;
00078                 TOS1 = pobj1;
00079                 continue;
00080 
00081             case ROT_THREE:
00082                 pobj1 = TOS;
00083                 TOS = TOS1;
00084                 TOS1 = TOS2;
00085                 TOS2 = pobj1;
00086                 continue;
00087 
00088             case DUP_TOP:
00089                 pobj1 = TOS;
00090                 PM_PUSH(pobj1);
00091                 continue;
00092 
00093             case ROT_FOUR:
00094                 pobj1 = TOS;
00095                 TOS = TOS1;
00096                 TOS1 = TOS2;
00097                 TOS2 = TOS3;
00098                 TOS3 = pobj1;
00099                 continue;
00100 
00101             case NOP:
00102                 continue;
00103 
00104             case UNARY_POSITIVE:
00105                 /* Raise TypeError if TOS is not an int */
00106                 if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
00107 #ifdef HAVE_FLOAT
00108                     && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_FLT)
00109 #endif /* HAVE_FLOAT */
00110                     )
00111                 {
00112                     PM_RAISE(retval, PM_RET_EX_TYPE);
00113                     break;
00114                 }
00115 
00116                 /* When TOS is an int, this is a no-op */
00117                 continue;
00118 
00119             case UNARY_NEGATIVE:
00120 #ifdef HAVE_FLOAT
00121                 if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
00122                 {
00123                     retval = float_negative(TOS, &pobj2);
00124                 }
00125                 else
00126 #endif /* HAVE_FLOAT */
00127                 {
00128                     retval = int_negative(TOS, &pobj2);
00129                 }
00130                 PM_BREAK_IF_ERROR(retval);
00131                 TOS = pobj2;
00132                 continue;
00133 
00134             case UNARY_NOT:
00135                 pobj1 = PM_POP();
00136                 if (obj_isFalse(pobj1))
00137                 {
00138                     PM_PUSH(PM_TRUE);
00139                 }
00140                 else
00141                 {
00142                     PM_PUSH(PM_FALSE);
00143                 }
00144                 continue;
00145 
00146 #ifdef HAVE_BACKTICK
00147             /* #244 Add support for the backtick operation (UNARY_CONVERT) */
00148             case UNARY_CONVERT:
00149                 retval = obj_repr(TOS, &pobj3);
00150                 PM_BREAK_IF_ERROR(retval);
00151                 TOS = pobj3;
00152                 continue;
00153 #endif /* HAVE_BACKTICK */
00154 
00155             case UNARY_INVERT:
00156                 /* Raise TypeError if it's not an int */
00157                 if (OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
00158                 {
00159                     PM_RAISE(retval, PM_RET_EX_TYPE);
00160                     break;
00161                 }
00162 
00163                 /* Otherwise perform bit-wise complement */
00164                 retval = int_bitInvert(TOS, &pobj2);
00165                 PM_BREAK_IF_ERROR(retval);
00166                 TOS = pobj2;
00167                 continue;
00168 
00169 #ifdef HAVE_PYTHON27
00170             case LIST_APPEND:
00171                 t16 = GET_ARG();
00172                 C_ASSERT(t16 >= 2); 
00173                 retval = list_append((*(PM_SP - t16)), TOS);
00174                 PM_SP--;
00175                 continue;
00176 
00177 #else /* HAVE_PYTHON27 */
00178             case LIST_APPEND:
00179                 /* list_append will raise a TypeError if TOS1 is not a list */
00180                 retval = list_append(TOS1, TOS);
00181                 PM_SP -= 2;
00182                 continue;
00183 #endif /* HAVE_PYTHON27 */
00184 
00185             case BINARY_POWER:
00186             case INPLACE_POWER:
00187 
00188 #ifdef HAVE_FLOAT
00189                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
00190                     || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
00191                 {
00192                     /* Calculate float power */
00193                     retval = float_op(TOS1, TOS, &pobj3, 'P');
00194                     PM_BREAK_IF_ERROR(retval);
00195                     PM_SP--;
00196                     TOS = pobj3;
00197                     continue;
00198                 }
00199 #endif /* HAVE_FLOAT */
00200 
00201                 /* Calculate integer power */
00202                 retval = int_pow(TOS1, TOS, &pobj3);
00203                 PM_BREAK_IF_ERROR(retval);
00204 
00205                 /* Set return value */
00206                 PM_SP--;
00207                 TOS = pobj3;
00208                 continue;
00209 
00210             case GET_ITER:
00211 #ifdef HAVE_GENERATORS
00212                 /* Raise TypeError if TOS is an instance, but not iterable */
00213                 if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
00214                 {
00215                     retval = class_getAttr(TOS, PM_NEXT_STR, &pobj1);
00216                     if (retval != PM_RET_OK)
00217                     {
00218                         PM_RAISE(retval, PM_RET_EX_TYPE);
00219                         break;
00220                     }
00221                 }
00222                 else
00223 #endif /* HAVE_GENERATORS */
00224                 {
00225                     /* Convert sequence to sequence-iterator */
00226                     retval = seqiter_new(TOS, &pobj1);
00227                     PM_BREAK_IF_ERROR(retval);
00228 
00229                     /* Put sequence-iterator on top of stack */
00230                     TOS = pobj1;
00231                 }
00232                 continue;
00233 
00234             case BINARY_MULTIPLY:
00235             case INPLACE_MULTIPLY:
00236                 /* If both objs are ints, perform the op */
00237                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00238                     && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
00239                 {
00240                     retval = int_new(((pPmInt_t)TOS1)->val *
00241                                      ((pPmInt_t)TOS)->val, &pobj3);
00242                     PM_BREAK_IF_ERROR(retval);
00243                     PM_SP--;
00244                     TOS = pobj3;
00245                     continue;
00246                 }
00247 
00248 #ifdef HAVE_FLOAT
00249                 else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
00250                          || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
00251                 {
00252                     retval = float_op(TOS1, TOS, &pobj3, '*');
00253                     PM_BREAK_IF_ERROR(retval);
00254                     PM_SP--;
00255                     TOS = pobj3;
00256                     continue;
00257                 }
00258 #endif /* HAVE_FLOAT */
00259 
00260 #ifdef HAVE_REPLICATION
00261                 /* If it's a list replication operation */
00262                 else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00263                          && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_LST))
00264                 {
00265                     t16 = (int16_t)((pPmInt_t)TOS)->val;
00266                     if (t16 < 0)
00267                     {
00268                         t16 = 0;
00269                     }
00270 
00271                     retval = list_replicate(TOS1, t16, &pobj3);
00272                     PM_BREAK_IF_ERROR(retval);
00273                     PM_SP--;
00274                     TOS = pobj3;
00275                     continue;
00276                 }
00277 
00278                 /* If it's a tuple replication operation */
00279                 else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00280                          && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_TUP))
00281                 {
00282                     t16 = (int16_t)((pPmInt_t)TOS)->val;
00283                     if (t16 < 0)
00284                     {
00285                         t16 = 0;
00286                     }
00287 
00288                     retval = tuple_replicate(TOS1, t16, &pobj3);
00289                     PM_BREAK_IF_ERROR(retval);
00290                     PM_SP--;
00291                     TOS = pobj3;
00292                     continue;
00293                 }
00294 
00295                 /* If it's a string replication operation */
00296                 else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00297                          && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_STR))
00298                 {
00299                     t16 = (int16_t)((pPmInt_t)TOS)->val;
00300                     if (t16 < 0)
00301                     {
00302                         t16 = 0;
00303                     }
00304 
00305                     pobj2 = TOS1;
00306                     pobj2 = (pPmObj_t)&((pPmString_t)pobj2)->val;
00307                     retval = string_replicate(
00308                         (uint8_t const **)(uint8_t *)&pobj2, t16, &pobj3);
00309                     PM_BREAK_IF_ERROR(retval);
00310                     PM_SP--;
00311                     TOS = pobj3;
00312                     continue;
00313                 }
00314 #endif /* HAVE_REPLICATION */
00315 
00316                 /* Otherwise raise a TypeError */
00317                 PM_RAISE(retval, PM_RET_EX_TYPE);
00318                 break;
00319 
00320             case BINARY_DIVIDE:
00321             case INPLACE_DIVIDE:
00322             case BINARY_FLOOR_DIVIDE:
00323             case INPLACE_FLOOR_DIVIDE:
00324 
00325 #ifdef HAVE_FLOAT
00326                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
00327                     || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
00328                 {
00329                     retval = float_op(TOS1, TOS, &pobj3, '/');
00330                     PM_BREAK_IF_ERROR(retval);
00331                     PM_SP--;
00332                     TOS = pobj3;
00333                     continue;
00334                 }
00335 #endif /* HAVE_FLOAT */
00336 
00337                 /* Otherwise perform operation */
00338                 retval = int_divmod(TOS1, TOS, '/', &pobj3);
00339                 PM_BREAK_IF_ERROR(retval);
00340                 PM_SP--;
00341                 TOS = pobj3;
00342                 continue;
00343 
00344             case BINARY_MODULO:
00345             case INPLACE_MODULO:
00346 
00347 #ifdef HAVE_STRING_FORMAT
00348                 /* If it's a string, perform string format */
00349                 if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_STR)
00350                 {
00351                     retval = string_format((pPmString_t)TOS1, TOS, &pobj3);
00352                     PM_BREAK_IF_ERROR(retval);
00353                     PM_SP--;
00354                     TOS = pobj3;
00355                     continue;
00356                 }
00357 #endif /* HAVE_STRING_FORMAT */
00358 
00359 #ifdef HAVE_FLOAT
00360                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
00361                     || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
00362                 {
00363                     retval = float_op(TOS1, TOS, &pobj3, '%');
00364                     PM_BREAK_IF_ERROR(retval);
00365                     PM_SP--;
00366                     TOS = pobj3;
00367                     continue;
00368                 }
00369 #endif /* HAVE_FLOAT */
00370 
00371                 /* Otherwise perform operation */
00372                 retval = int_divmod(TOS1, TOS, '%', &pobj3);
00373                 PM_BREAK_IF_ERROR(retval);
00374                 PM_SP--;
00375                 TOS = pobj3;
00376                 continue;
00377 
00378             case STORE_MAP:
00379                 /* #213: Add support for Python 2.6 bytecodes */
00380                 C_ASSERT(OBJ_GET_TYPE(TOS2) == OBJ_TYPE_DIC);
00381                 retval = dict_setItem(TOS2, TOS, TOS1);
00382                 PM_BREAK_IF_ERROR(retval);
00383                 PM_SP -= 2;
00384                 continue;
00385 
00386             case BINARY_ADD:
00387             case INPLACE_ADD:
00388 
00389 #ifdef HAVE_FLOAT
00390                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
00391                     || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
00392                 {
00393                     retval = float_op(TOS1, TOS, &pobj3, '+');
00394                     PM_BREAK_IF_ERROR(retval);
00395                     PM_SP--;
00396                     TOS = pobj3;
00397                     continue;
00398                 }
00399 #endif /* HAVE_FLOAT */
00400 
00401                 /* If both objs are ints, perform the op */
00402                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00403                     && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
00404                 {
00405                     retval = int_new(((pPmInt_t)TOS1)->val +
00406                                      ((pPmInt_t)TOS)->val, &pobj3);
00407                     PM_BREAK_IF_ERROR(retval);
00408                     PM_SP--;
00409                     TOS = pobj3;
00410                     continue;
00411                 }
00412 
00413                 /* #242: If both objs are strings, perform concatenation */
00414                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_STR)
00415                     && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_STR))
00416                 {
00417                     retval = string_concat((pPmString_t)TOS1,
00418                                            (pPmString_t)TOS,
00419                                            &pobj3);
00420                     PM_BREAK_IF_ERROR(retval);
00421                     PM_SP--;
00422                     TOS = pobj3;
00423                     continue;
00424                 }
00425 
00426                 /* Otherwise raise a TypeError */
00427                 PM_RAISE(retval, PM_RET_EX_TYPE);
00428                 break;
00429 
00430             case BINARY_SUBTRACT:
00431             case INPLACE_SUBTRACT:
00432 
00433 #ifdef HAVE_FLOAT
00434                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
00435                     || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
00436                 {
00437                     retval = float_op(TOS1, TOS, &pobj3, '-');
00438                     PM_BREAK_IF_ERROR(retval);
00439                     PM_SP--;
00440                     TOS = pobj3;
00441                     continue;
00442                 }
00443 #endif /* HAVE_FLOAT */
00444 
00445                 /* If both objs are ints, perform the op */
00446                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00447                     && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
00448                 {
00449                     retval = int_new(((pPmInt_t)TOS1)->val -
00450                                      ((pPmInt_t)TOS)->val, &pobj3);
00451                     PM_BREAK_IF_ERROR(retval);
00452                     PM_SP--;
00453                     TOS = pobj3;
00454                     continue;
00455                 }
00456 
00457                 /* Otherwise raise a TypeError */
00458                 PM_RAISE(retval, PM_RET_EX_TYPE);
00459                 break;
00460 
00461             case BINARY_SUBSCR:
00462                 /* Implements TOS = TOS1[TOS]. */
00463 
00464                 if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_DIC)
00465                 {
00466                     retval = dict_getItem(TOS1, TOS, &pobj3);
00467                 }
00468                 else
00469                 {
00470                     /* Raise a TypeError if index is not an Integer or Bool */
00471                     if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
00472                         && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_BOOL))
00473                     {
00474                         PM_RAISE(retval, PM_RET_EX_TYPE);
00475                         break;
00476                     }
00477 
00478                     pobj1 = TOS1;
00479 #ifdef HAVE_BYTEARRAY
00480                     /* If object is an instance, get the thing it contains */
00481                     if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_CLI)
00482                     {
00483                         retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj1)->cli_attrs,
00484                                               PM_NONE,
00485                                               &pobj2);
00486                         PM_RETURN_IF_ERROR(retval);
00487                         pobj1 = pobj2;
00488                     }
00489 #endif /* HAVE_BYTEARRAY */
00490 
00491                     /* Ensure the index doesn't overflow */
00492                     C_ASSERT(((pPmInt_t)TOS)->val <= 0x0000FFFF);
00493                     t16 = (int16_t)((pPmInt_t)TOS)->val;
00494 
00495                     retval = seq_getSubscript(pobj1, t16, &pobj3);
00496                 }
00497                 PM_BREAK_IF_ERROR(retval);
00498                 PM_SP--;
00499                 TOS = pobj3;
00500                 continue;
00501 
00502 #ifdef HAVE_FLOAT
00503             /* #213: Add support for Python 2.6 bytecodes */
00504             case BINARY_TRUE_DIVIDE:
00505             case INPLACE_TRUE_DIVIDE:
00506 
00507                 /* Perform division; float_op() checks for types and zero-div */
00508                 retval = float_op(TOS1, TOS, &pobj3, '/');
00509                 PM_BREAK_IF_ERROR(retval);
00510                 PM_SP--;
00511                 TOS = pobj3;
00512                 continue;
00513 #endif /* HAVE_FLOAT */
00514 
00515             case SLICE_0:
00516                 /* Implements TOS = TOS[:], push a copy of the sequence */
00517 
00518                 /* Create a copy if it is a list */
00519                 if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_LST)
00520                 {
00521                     retval = list_copy(TOS, &pobj2);
00522                     PM_BREAK_IF_ERROR(retval);
00523 
00524                     TOS = pobj2;
00525                 }
00526 
00527                 /* If TOS is an immutable sequence leave it (no op) */
00528 
00529                 /* Raise a TypeError for types that can not be sliced */
00530                 else if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_STR)
00531                          && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_TUP))
00532                 {
00533                     PM_RAISE(retval, PM_RET_EX_TYPE);
00534                     break;
00535                 }
00536                 continue;
00537 
00538             case STORE_SUBSCR:
00539                 /* Implements TOS1[TOS] = TOS2 */
00540 
00541                 /* If it's a list */
00542                 if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_LST)
00543                 {
00544                     /* Ensure subscr is an int or bool */
00545                     if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
00546                         && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_BOOL))
00547                     {
00548                         PM_RAISE(retval, PM_RET_EX_TYPE);
00549                         break;
00550                     }
00551 
00552                     /* Set the list item */
00553                     retval = list_setItem(TOS1,
00554                                           (int16_t)(((pPmInt_t)TOS)->val),
00555                                           TOS2);
00556                     PM_BREAK_IF_ERROR(retval);
00557                     PM_SP -= 3;
00558                     continue;
00559                 }
00560 
00561                 /* If it's a dict */
00562                 if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_DIC)
00563                 {
00564                     /* Set the dict item */
00565                     retval = dict_setItem(TOS1, TOS, TOS2);
00566                     PM_BREAK_IF_ERROR(retval);
00567                     PM_SP -= 3;
00568                     continue;
00569                 }
00570 
00571 #ifdef HAVE_BYTEARRAY
00572                 /* If object is an instance, get the thing it contains */
00573                 if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_CLI)
00574                 {
00575                     retval = dict_getItem((pPmObj_t)((pPmInstance_t)TOS1)->cli_attrs,
00576                                           PM_NONE,
00577                                           &pobj2);
00578 
00579                     /* Raise TypeError if instance isn't a ByteArray */
00580                     if ((retval == PM_RET_EX_KEY)
00581                         || (OBJ_GET_TYPE(pobj2) != OBJ_TYPE_BYA))
00582                     {
00583                         PM_RAISE(retval, PM_RET_EX_TYPE);
00584                         break;
00585                     }
00586                     PM_BREAK_IF_ERROR(retval);
00587 
00588                     /* Ensure subscr is an int or bool */
00589                     if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
00590                         && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_BOOL))
00591                     {
00592                         PM_RAISE(retval, PM_RET_EX_TYPE);
00593                         break;
00594                     }
00595 
00596                     retval = bytearray_setItem(pobj2,
00597                                                (int16_t)(((pPmInt_t)TOS)->val),
00598                                                TOS2);
00599                     PM_BREAK_IF_ERROR(retval);
00600                     PM_SP -= 3;
00601                     continue;
00602                 }
00603 #endif /* HAVE_BYTEARRAY */
00604 
00605                 /* TypeError for all else */
00606                 PM_RAISE(retval, PM_RET_EX_TYPE);
00607                 break;
00608 
00609 #ifdef HAVE_DEL
00610             case DELETE_SUBSCR:
00611 
00612                 if ((OBJ_GET_TYPE(TOS1) == OBJ_TYPE_LST)
00613                     && (OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT))
00614                 {
00615                     retval = list_delItem(TOS1,
00616                                           (int16_t)((pPmInt_t)TOS)->val);
00617                 }
00618 
00619                 else if ((OBJ_GET_TYPE(TOS1) == OBJ_TYPE_DIC)
00620                          && (OBJ_GET_TYPE(TOS) <= OBJ_TYPE_HASHABLE_MAX))
00621                 {
00622                     retval = dict_delItem(TOS1, TOS);
00623                 }
00624 
00625                 /* Raise TypeError if obj is not a list or dict */
00626                 else
00627                 {
00628                     PM_RAISE(retval, PM_RET_EX_TYPE);
00629                 }
00630 
00631                 PM_BREAK_IF_ERROR(retval);
00632                 PM_SP -= 2;
00633                 continue;
00634 #endif /* HAVE_DEL */
00635 
00636             case BINARY_LSHIFT:
00637             case INPLACE_LSHIFT:
00638                 /* If both objs are ints, perform the op */
00639                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00640                     && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
00641                 {
00642                     retval = int_new(((pPmInt_t)TOS1)->val <<
00643                                      ((pPmInt_t)TOS)->val, &pobj3);
00644                     PM_BREAK_IF_ERROR(retval);
00645                     PM_SP--;
00646                     TOS = pobj3;
00647                     continue;
00648                 }
00649 
00650                 /* Otherwise raise a TypeError */
00651                 PM_RAISE(retval, PM_RET_EX_TYPE);
00652                 break;
00653 
00654             case BINARY_RSHIFT:
00655             case INPLACE_RSHIFT:
00656                 /* If both objs are ints, perform the op */
00657                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00658                     && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
00659                 {
00660                     retval = int_new(((pPmInt_t)TOS1)->val >>
00661                                      ((pPmInt_t)TOS)->val, &pobj3);
00662                     PM_BREAK_IF_ERROR(retval);
00663                     PM_SP--;
00664                     TOS = pobj3;
00665                     continue;
00666                 }
00667 
00668                 /* Otherwise raise a TypeError */
00669                 PM_RAISE(retval, PM_RET_EX_TYPE);
00670                 break;
00671 
00672             case BINARY_AND:
00673             case INPLACE_AND:
00674                 /* If both objs are ints, perform the op */
00675                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00676                     && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
00677                 {
00678                     retval = int_new(((pPmInt_t)TOS1)->val &
00679                                      ((pPmInt_t)TOS)->val, &pobj3);
00680                     PM_BREAK_IF_ERROR(retval);
00681                     PM_SP--;
00682                     TOS = pobj3;
00683                     continue;
00684                 }
00685 
00686                 /* Otherwise raise a TypeError */
00687                 PM_RAISE(retval, PM_RET_EX_TYPE);
00688                 break;
00689 
00690             case BINARY_XOR:
00691             case INPLACE_XOR:
00692                 /* If both objs are ints, perform the op */
00693                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00694                     && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
00695                 {
00696                     retval = int_new(((pPmInt_t)TOS1)->val ^
00697                                      ((pPmInt_t)TOS)->val, &pobj3);
00698                     PM_BREAK_IF_ERROR(retval);
00699                     PM_SP--;
00700                     TOS = pobj3;
00701                     continue;
00702                 }
00703 
00704                 /* Otherwise raise a TypeError */
00705                 PM_RAISE(retval, PM_RET_EX_TYPE);
00706                 break;
00707 
00708             case BINARY_OR:
00709             case INPLACE_OR:
00710                 /* If both objs are ints, perform the op */
00711                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00712                     && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
00713                 {
00714                     retval = int_new(((pPmInt_t)TOS1)->val |
00715                                      ((pPmInt_t)TOS)->val, &pobj3);
00716                     PM_BREAK_IF_ERROR(retval);
00717                     PM_SP--;
00718                     TOS = pobj3;
00719                     continue;
00720                 }
00721 
00722                 /* Otherwise raise a TypeError */
00723                 PM_RAISE(retval, PM_RET_EX_TYPE);
00724                 break;
00725 
00726 #ifdef HAVE_PRINT
00727             case PRINT_EXPR:
00728                 /* Print interactive expression */
00729                 /* Fallthrough */
00730 
00731             case PRINT_ITEM:
00732                 if (gVmGlobal.needSoftSpace && (bc == PRINT_ITEM))
00733                 {
00734                     retval = plat_putByte(' ');
00735                     PM_BREAK_IF_ERROR(retval);
00736                 }
00737                 gVmGlobal.needSoftSpace = C_TRUE;
00738 
00739                 /* Print out topmost stack element */
00740                 retval = obj_print(TOS, (uint8_t)(bc == PRINT_EXPR), C_FALSE);
00741                 PM_BREAK_IF_ERROR(retval);
00742                 PM_SP--;
00743                 if (bc != PRINT_EXPR)
00744                 {
00745                     continue;
00746                 }
00747                 /* If PRINT_EXPR, Fallthrough to print a newline */
00748 
00749             case PRINT_NEWLINE:
00750                 gVmGlobal.needSoftSpace = C_FALSE;
00751                 if (gVmGlobal.somethingPrinted)
00752                 {
00753                     retval = plat_putByte('\n');
00754                     gVmGlobal.somethingPrinted = C_FALSE;
00755                 }
00756                 PM_BREAK_IF_ERROR(retval);
00757                 continue;
00758 #endif /* HAVE_PRINT */
00759 
00760             case BREAK_LOOP:
00761             {
00762                 pPmBlock_t pb1 = PM_FP->fo_blockstack;
00763 
00764                 /* Ensure there's a block */
00765                 C_ASSERT(pb1 != C_NULL);
00766 
00767                 /* Delete blocks until first loop block */
00768                 while ((pb1->b_type != B_LOOP) && (pb1->next != C_NULL))
00769                 {
00770                     pobj2 = (pPmObj_t)pb1;
00771                     pb1 = pb1->next;
00772                     retval = heap_freeChunk(pobj2);
00773                     PM_BREAK_IF_ERROR(retval);
00774                 }
00775 
00776                 /* Test again outside while loop */
00777                 PM_BREAK_IF_ERROR(retval);
00778 
00779                 /* Restore PM_SP */
00780                 PM_SP = pb1->b_sp;
00781 
00782                 /* Goto handler */
00783                 PM_IP = pb1->b_handler;
00784 
00785                 /* Pop and delete this block */
00786                 PM_FP->fo_blockstack = pb1->next;
00787                 retval = heap_freeChunk((pPmObj_t)pb1);
00788                 PM_BREAK_IF_ERROR(retval);
00789             }
00790                 continue;
00791 
00792             case LOAD_LOCALS:
00793                 /* Pushes local attrs dict of current frame */
00794                 /* WARNING: does not copy fo_locals to attrs */
00795                 PM_PUSH((pPmObj_t)PM_FP->fo_attrs);
00796                 continue;
00797 
00798             case RETURN_VALUE:
00799                 /* Get expiring frame's TOS */
00800                 pobj2 = PM_POP();
00801 
00802 #if 0 /*__DEBUG__*/
00803                 /* #251: This safety check is disabled because it breaks ipm */
00804                 /* #109: Check that stack should now be empty */
00805                 /* If this is regular frame (not native and not a generator) */
00806                 if ((PM_FP != (pPmFrame_t)(&gVmGlobal.nativeframe)) &&
00807                     !(PM_FP->fo_func->f_co->co_flags & CO_GENERATOR))
00808                 {
00809                     /* An empty stack points one past end of locals */
00810                     t8 = PM_FP->fo_func->f_co->co_nlocals;
00811                     C_ASSERT(PM_SP == &(PM_FP->fo_locals[t8]));
00812                 }
00813 #endif /* __DEBUG__ */
00814 
00815                 /* Keep ref of expiring frame */
00816                 pobj1 = (pPmObj_t)PM_FP;
00817                 C_ASSERT(OBJ_GET_TYPE(pobj1) == OBJ_TYPE_FRM);
00818 
00819                 /* If no previous frame, quit thread */
00820                 if (PM_FP->fo_back == C_NULL)
00821                 {
00822                     gVmGlobal.pthread->interpctrl = INTERP_CTRL_EXIT;
00823                     retval = PM_RET_OK;
00824                     break;
00825                 }
00826 
00827                 /* Otherwise return to previous frame */
00828                 PM_FP = PM_FP->fo_back;
00829 
00830 #ifdef HAVE_GENERATORS
00831                 /* If returning function was a generator */
00832                 if (((pPmFrame_t)pobj1)->fo_func->f_co->co_flags & CO_GENERATOR)
00833                 {
00834                     /* Raise a StopIteration exception */
00835                     PM_RAISE(retval, PM_RET_EX_STOP);
00836                     break;
00837                 }
00838 #endif /* HAVE_GENERATORS */
00839 
00840 #ifdef HAVE_CLASSES
00841                 /*
00842                  * If returning function was class initializer
00843                  * do not push a return object
00844                  */
00845                 if (((pPmFrame_t)pobj1)->fo_isInit)
00846                 {
00847                     /* Raise TypeError if __init__ did not return None */
00848                     if (pobj2 != PM_NONE)
00849                     {
00850                         PM_RAISE(retval, PM_RET_EX_TYPE);
00851                         break;
00852                     }
00853                 }
00854                 else
00855 #endif /* HAVE_CLASSES */
00856 
00857                 /*
00858                  * Push frame's return val, except if the expiring frame
00859                  * was due to an import statement
00860                  */
00861                 if (!(((pPmFrame_t)pobj1)->fo_isImport))
00862                 {
00863                     PM_PUSH(pobj2);
00864                 }
00865 
00866                 /* Deallocate expired frame */
00867                 PM_BREAK_IF_ERROR(heap_freeChunk(pobj1));
00868                 continue;
00869 
00870 #ifdef HAVE_IMPORTS
00871             case IMPORT_STAR:
00872                 /* #102: Implement the remaining IMPORT_ bytecodes */
00873                 /* Expect a module on the top of the stack */
00874                 C_ASSERT(OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD);
00875 
00876                 /* Update PM_FP's attrs with those of the module on the stack */
00877                 retval = dict_update((pPmObj_t)PM_FP->fo_attrs,
00878                                      (pPmObj_t)((pPmFunc_t)TOS)->f_attrs,
00879                                      C_TRUE);
00880                 PM_BREAK_IF_ERROR(retval);
00881                 PM_SP--;
00882                 continue;
00883 #endif /* HAVE_IMPORTS */
00884 
00885 #ifdef HAVE_GENERATORS
00886             case YIELD_VALUE:
00887                 /* #207: Add support for the yield keyword */
00888                 /* Get expiring frame's TOS */
00889                 pobj1 = PM_POP();
00890 
00891                 /* Raise TypeError if __init__ did not return None */
00892                 /* (Yield means this is a generator) */
00893                 if ((PM_FP)->fo_isInit)
00894                 {
00895                     PM_RAISE(retval, PM_RET_EX_TYPE);
00896                     break;
00897                 }
00898 
00899                 /* Return to previous frame */
00900                 PM_FP = PM_FP->fo_back;
00901 
00902                 /* Push yield value onto caller's TOS */
00903                 PM_PUSH(pobj1);
00904                 continue;
00905 #endif /* HAVE_GENERATORS */
00906 
00907             case POP_BLOCK:
00908                 /* Get ptr to top block */
00909                 pobj1 = (pPmObj_t)PM_FP->fo_blockstack;
00910 
00911                 /* If there's no block, raise SystemError */
00912                 C_ASSERT(pobj1 != C_NULL);
00913 
00914                 /* Pop block */
00915                 PM_FP->fo_blockstack = PM_FP->fo_blockstack->next;
00916 
00917                 /* Set stack to previous level, jump to code outside block */
00918                 PM_SP = ((pPmBlock_t)pobj1)->b_sp;
00919                 PM_IP = ((pPmBlock_t)pobj1)->b_handler;
00920 
00921                 PM_BREAK_IF_ERROR(heap_freeChunk(pobj1));
00922                 continue;
00923 
00924 #ifdef HAVE_CLASSES
00925             case BUILD_CLASS:
00926                 /* Create and push new class */
00927                 retval = class_new(TOS, TOS1, TOS2, &pobj2);
00928                 PM_BREAK_IF_ERROR(retval);
00929                 PM_SP -= 2;
00930                 TOS = pobj2;
00931                 continue;
00932 #endif /* HAVE_CLASSES */
00933 
00934 
00935             /***************************************************
00936              * All bytecodes after 90 (0x5A) have a 2-byte arg
00937              * that needs to be swallowed using GET_ARG().
00938              **************************************************/
00939 
00940             case STORE_NAME:
00941                 /* Get name index */
00942                 t16 = GET_ARG();
00943 
00944                 /* Get key */
00945                 pobj2 = PM_FP->fo_func->f_co->co_names->val[t16];
00946 
00947                 /* Set key=val in current frame's attrs dict */
00948                 retval = dict_setItem((pPmObj_t)PM_FP->fo_attrs, pobj2, TOS);
00949                 PM_BREAK_IF_ERROR(retval);
00950                 PM_SP--;
00951                 continue;
00952 
00953 #ifdef HAVE_DEL
00954             case DELETE_NAME:
00955                 /* Get name index */
00956                 t16 = GET_ARG();
00957 
00958                 /* Get key */
00959                 pobj2 = PM_FP->fo_func->f_co->co_names->val[t16];
00960 
00961                 /* Remove key,val pair from current frame's attrs dict */
00962                 retval = dict_delItem((pPmObj_t)PM_FP->fo_attrs, pobj2);
00963                 PM_BREAK_IF_ERROR(retval);
00964                 continue;
00965 #endif /* HAVE_DEL */
00966 
00967             case UNPACK_SEQUENCE:
00968                 /* Get ptr to sequence */
00969                 pobj1 = PM_POP();
00970 
00971 #ifdef HAVE_BYTEARRAY
00972                 /* If object is an instance, get the thing it contains */
00973                 if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_CLI)
00974                 {
00975                     retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj1)->cli_attrs,
00976                                           PM_NONE,
00977                                           &pobj2);
00978                     PM_RETURN_IF_ERROR(retval);
00979                     pobj1 = pobj2;
00980                 }
00981 #endif /* HAVE_BYTEARRAY */
00982 
00983                 /*
00984                  * Get the length of the sequence; this will
00985                  * raise TypeError if obj is not a sequence.
00986                  *
00987                  * #59: Unpacking to a Dict shall not be supported
00988                  */
00989                 retval = seq_getLength(pobj1, (uint16_t *)&t16);
00990                 if (retval != PM_RET_OK)
00991                 {
00992                     GET_ARG();
00993                     break;
00994                 }
00995 
00996                 /* Raise ValueError if seq length does not match num args */
00997                 if (t16 != GET_ARG())
00998                 {
00999                     PM_RAISE(retval, PM_RET_EX_VAL);
01000                     break;
01001                 }
01002 
01003                 /* Push sequence's objs onto stack */
01004                 for (; --t16 >= 0;)
01005                 {
01006                     retval = seq_getSubscript(pobj1, t16, &pobj2);
01007                     PM_BREAK_IF_ERROR(retval);
01008                     PM_PUSH(pobj2);
01009                 }
01010 
01011                 /* Test again outside the for loop */
01012                 PM_BREAK_IF_ERROR(retval);
01013                 continue;
01014 
01015             case FOR_ITER:
01016                 t16 = GET_ARG();
01017 
01018 #ifdef HAVE_GENERATORS
01019                 /* If TOS is an instance, call next method */
01020                 if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
01021                 {
01022                     /* Get the next() func */
01023                     retval = class_getAttr(TOS, PM_NEXT_STR, &pobj1);
01024                     PM_BREAK_IF_ERROR(retval);
01025 
01026                     /* Push the func and instance as an arg */
01027                     pobj2 = TOS;
01028                     PM_PUSH(pobj1);
01029                     PM_PUSH(pobj2);
01030                     t16 = 1;
01031 
01032                     /* Ensure pobj1 is the func */
01033                     goto CALL_FUNC_FOR_ITER;
01034                 }
01035                 else
01036 #endif /* HAVE_GENERATORS */
01037                 {
01038                     /* Get the next item in the sequence iterator */
01039                     retval = seqiter_getNext(TOS, &pobj2);
01040                 }
01041 
01042                 /* Catch StopIteration early: pop iterator and break loop */
01043                 if (retval == PM_RET_EX_STOP)
01044                 {
01045                     PM_SP--;
01046                     retval = PM_RET_OK;
01047                     PM_IP += t16;
01048                     continue;
01049                 }
01050                 PM_BREAK_IF_ERROR(retval);
01051 
01052                 /* Push the next item onto the stack */
01053                 PM_PUSH(pobj2);
01054                 continue;
01055 
01056             case STORE_ATTR:
01057                 /* TOS.name = TOS1 */
01058                 /* Get names index */
01059                 t16 = GET_ARG();
01060 
01061                 /* Get attrs dict from obj */
01062                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FXN)
01063                     || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD))
01064                 {
01065                     pobj2 = (pPmObj_t)((pPmFunc_t)TOS)->f_attrs;
01066                 }
01067 
01068 #ifdef HAVE_CLASSES
01069                 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO)
01070                 {
01071                     pobj2 = (pPmObj_t)((pPmClass_t)TOS)->cl_attrs;
01072                 }
01073                 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
01074                 {
01075                     pobj2 = (pPmObj_t)((pPmInstance_t)TOS)->cli_attrs;
01076                 }
01077                 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MTH)
01078                 {
01079                     pobj2 = (pPmObj_t)((pPmMethod_t)TOS)->m_attrs;
01080                 }
01081 #endif /* HAVE_CLASSES */
01082 
01083                 /* Other types result in an AttributeError */
01084                 else
01085                 {
01086                     PM_RAISE(retval, PM_RET_EX_ATTR);
01087                     break;
01088                 }
01089 
01090                 /* If attrs is not a dict, raise SystemError */
01091                 if (OBJ_GET_TYPE(pobj2) != OBJ_TYPE_DIC)
01092                 {
01093                     PM_RAISE(retval, PM_RET_EX_SYS);
01094                     break;
01095                 }
01096 
01097                 /* Get name/key obj */
01098                 pobj3 = PM_FP->fo_func->f_co->co_names->val[t16];
01099 
01100                 /* Set key=val in obj's dict */
01101                 retval = dict_setItem(pobj2, pobj3, TOS1);
01102                 PM_BREAK_IF_ERROR(retval);
01103                 PM_SP -= 2;
01104                 continue;
01105 
01106 #ifdef HAVE_DEL
01107             case DELETE_ATTR:
01108                 /* del TOS.name */
01109                 /* Get names index */
01110                 t16 = GET_ARG();
01111 
01112                 /* Get attrs dict from obj */
01113                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FXN)
01114                     || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD))
01115                 {
01116                     pobj2 = (pPmObj_t)((pPmFunc_t)TOS)->f_attrs;
01117                 }
01118 
01119 #ifdef HAVE_CLASSES
01120                 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO)
01121                 {
01122                     pobj2 = (pPmObj_t)((pPmClass_t)TOS)->cl_attrs;
01123                 }
01124                 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
01125                 {
01126                     pobj2 = (pPmObj_t)((pPmInstance_t)TOS)->cli_attrs;
01127                 }
01128                 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MTH)
01129                 {
01130                     pobj2 = (pPmObj_t)((pPmMethod_t)TOS)->m_attrs;
01131                 }
01132 #endif /* HAVE_CLASSES */
01133 
01134                 /* Other types result in an AttributeError */
01135                 else
01136                 {
01137                     PM_RAISE(retval, PM_RET_EX_ATTR);
01138                     break;
01139                 }
01140 
01141                 /* If attrs is not a dict, raise SystemError */
01142                 if (OBJ_GET_TYPE(pobj2) != OBJ_TYPE_DIC)
01143                 {
01144                     PM_RAISE(retval, PM_RET_EX_SYS);
01145                     break;
01146                 }
01147 
01148                 /* Get name/key obj */
01149                 pobj3 = PM_FP->fo_func->f_co->co_names->val[t16];
01150 
01151                 /* Remove key,val from obj's dict */
01152                 retval = dict_delItem(pobj2, pobj3);
01153 
01154                 /* Raise an AttributeError if key is not found */
01155                 if (retval == PM_RET_EX_KEY)
01156                 {
01157                     PM_RAISE(retval, PM_RET_EX_ATTR);
01158                 }
01159 
01160                 PM_BREAK_IF_ERROR(retval);
01161                 PM_SP--;
01162                 continue;
01163 #endif /* HAVE_DEL */
01164 
01165             case STORE_GLOBAL:
01166                 /* Get name index */
01167                 t16 = GET_ARG();
01168 
01169                 /* Get key */
01170                 pobj2 = PM_FP->fo_func->f_co->co_names->val[t16];
01171 
01172                 /* Set key=val in global dict */
01173                 retval = dict_setItem((pPmObj_t)PM_FP->fo_globals, pobj2, TOS);
01174                 PM_BREAK_IF_ERROR(retval);
01175                 PM_SP--;
01176                 continue;
01177 
01178 #ifdef HAVE_DEL
01179             case DELETE_GLOBAL:
01180                 /* Get name index */
01181                 t16 = GET_ARG();
01182 
01183                 /* Get key */
01184                 pobj2 = PM_FP->fo_func->f_co->co_names->val[t16];
01185 
01186                 /* Remove key,val from globals */
01187                 retval = dict_delItem((pPmObj_t)PM_FP->fo_globals, pobj2);
01188                 PM_BREAK_IF_ERROR(retval);
01189                 continue;
01190 #endif /* HAVE_DEL */
01191 
01192             case DUP_TOPX:
01193                 t16 = GET_ARG();
01194                 C_ASSERT(t16 <= 3);
01195 
01196                 pobj1 = TOS;
01197                 pobj2 = TOS1;
01198                 pobj3 = TOS2;
01199                 if (t16 >= 3)
01200                     PM_PUSH(pobj3);
01201                 if (t16 >= 2)
01202                     PM_PUSH(pobj2);
01203                 if (t16 >= 1)
01204                     PM_PUSH(pobj1);
01205                 continue;
01206 
01207             case LOAD_CONST:
01208                 /* Get const's index in CO */
01209                 t16 = GET_ARG();
01210 
01211                 /* Push const on stack */
01212                 PM_PUSH(PM_FP->fo_func->f_co->co_consts->val[t16]);
01213                 continue;
01214 
01215             case LOAD_NAME:
01216                 /* Get name index */
01217                 t16 = GET_ARG();
01218 
01219                 /* Get name from names tuple */
01220                 pobj1 = PM_FP->fo_func->f_co->co_names->val[t16];
01221 
01222                 /* Get value from frame's attrs dict */
01223                 retval = dict_getItem((pPmObj_t)PM_FP->fo_attrs, pobj1, &pobj2);
01224                 if (retval == PM_RET_EX_KEY)
01225                 {
01226                     /* Get val from globals */
01227                     retval = dict_getItem((pPmObj_t)PM_FP->fo_globals,
01228                                           pobj1, &pobj2);
01229 
01230                     /* Check for name in the builtins module if it is loaded */
01231                     if ((retval == PM_RET_EX_KEY) && (PM_PBUILTINS != C_NULL))
01232                     {
01233                         /* Get val from builtins */
01234                         retval = dict_getItem(PM_PBUILTINS, pobj1, &pobj2);
01235                         if (retval == PM_RET_EX_KEY)
01236                         {
01237                             /* Name not defined, raise NameError */
01238                             PM_RAISE(retval, PM_RET_EX_NAME);
01239                             break;
01240                         }
01241                     }
01242                 }
01243                 PM_BREAK_IF_ERROR(retval);
01244                 PM_PUSH(pobj2);
01245                 continue;
01246 
01247             case BUILD_TUPLE:
01248                 /* Get num items */
01249                 t16 = GET_ARG();
01250                 retval = tuple_new(t16, &pobj1);
01251                 PM_BREAK_IF_ERROR(retval);
01252 
01253                 /* Fill tuple with ptrs to objs */
01254                 for (; --t16 >= 0;)
01255                 {
01256                     ((pPmTuple_t)pobj1)->val[t16] = PM_POP();
01257                 }
01258                 PM_PUSH(pobj1);
01259                 continue;
01260 
01261             case BUILD_LIST:
01262                 t16 = GET_ARG();
01263                 retval = list_new(&pobj1);
01264                 PM_BREAK_IF_ERROR(retval);
01265                 for (; --t16 >= 0;)
01266                 {
01267                     /* Insert obj into list */
01268                     heap_gcPushTempRoot(pobj1, &objid);
01269                     retval = list_insert(pobj1, 0, TOS);
01270                     heap_gcPopTempRoot(objid);
01271                     PM_BREAK_IF_ERROR(retval);
01272                     PM_SP--;
01273                 }
01274                 /* Test again outside for loop */
01275                 PM_BREAK_IF_ERROR(retval);
01276 
01277                 /* push list onto stack */
01278                 PM_PUSH(pobj1);
01279                 continue;
01280 
01281             case BUILD_MAP:
01282                 /* Argument is ignored */
01283                 t16 = GET_ARG();
01284                 retval = dict_new(&pobj1);
01285                 PM_BREAK_IF_ERROR(retval);
01286                 PM_PUSH(pobj1);
01287                 continue;
01288 
01289             case LOAD_ATTR:
01290                 /* Implements TOS.attr */
01291                 t16 = GET_ARG();
01292 
01293 #ifdef HAVE_AUTOBOX
01294                 /* Autobox the object, if necessary */
01295                 retval = class_autobox(&TOS);
01296                 PM_BREAK_IF_ERROR(retval);
01297 #endif
01298 
01299                 /* Get attrs dict from obj */
01300                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FXN) ||
01301                     (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD))
01302                 {
01303                     pobj1 = (pPmObj_t)((pPmFunc_t)TOS)->f_attrs;
01304                 }
01305 
01306 #ifdef HAVE_CLASSES
01307                 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO)
01308                 {
01309                     pobj1 = (pPmObj_t)((pPmClass_t)TOS)->cl_attrs;
01310                 }
01311                 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
01312                 {
01313                     pobj1 = (pPmObj_t)((pPmInstance_t)TOS)->cli_attrs;
01314                 }
01315                 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MTH)
01316                 {
01317                     pobj1 = (pPmObj_t)((pPmMethod_t)TOS)->m_attrs;
01318                 }
01319 #endif /* HAVE_CLASSES */
01320 
01321                 /* Other types result in an AttributeError */
01322                 else
01323                 {
01324                     PM_RAISE(retval, PM_RET_EX_ATTR);
01325                     break;
01326                 }
01327 
01328                 /* If attrs is not a dict, raise SystemError */
01329                 if (OBJ_GET_TYPE(pobj1) != OBJ_TYPE_DIC)
01330                 {
01331                     PM_RAISE(retval, PM_RET_EX_SYS);
01332                     break;
01333                 }
01334 
01335                 /* Get name */
01336                 pobj2 = PM_FP->fo_func->f_co->co_names->val[t16];
01337 
01338                 /* Get attr with given name */
01339                 retval = dict_getItem(pobj1, pobj2, &pobj3);
01340 
01341 #ifdef HAVE_CLASSES
01342                 /*
01343                  * If attr is not found and object is a class or instance,
01344                  * try to get the attribute from the class attrs or parent(s)
01345                  */
01346                 if ((retval == PM_RET_EX_KEY) &&
01347                     ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO)
01348                         || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)))
01349                 {
01350                     retval = class_getAttr(TOS, pobj2, &pobj3);
01351                 }
01352 #endif /* HAVE_CLASSES */
01353 
01354                 /* Raise an AttributeError if key is not found */
01355                 if (retval == PM_RET_EX_KEY)
01356                 {
01357                     PM_RAISE(retval, PM_RET_EX_ATTR);
01358                 }
01359                 PM_BREAK_IF_ERROR(retval);
01360 
01361 #ifdef HAVE_CLASSES
01362                 /* If obj is an instance and attr is a func, create method */
01363                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI) &&
01364                     (OBJ_GET_TYPE(pobj3) == OBJ_TYPE_FXN))
01365                 {
01366                     pobj2 = pobj3;
01367                     retval = class_method(TOS, pobj2, &pobj3);
01368                     PM_BREAK_IF_ERROR(retval);
01369                 }
01370 #endif /* HAVE_CLASSES */
01371 
01372                 /* Put attr on the stack */
01373                 TOS = pobj3;
01374                 continue;
01375 
01376             case COMPARE_OP:
01377                 retval = PM_RET_OK;
01378                 t16 = GET_ARG();
01379 
01380 #ifdef HAVE_FLOAT
01381                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
01382                     || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
01383                 {
01384                     retval = float_compare(TOS1, TOS, &pobj3, (PmCompare_t)t16);
01385                     PM_SP--;
01386                     TOS = pobj3;
01387                     continue;
01388                 }
01389 #endif /* HAVE_FLOAT */
01390 
01391                 /* Handle all integer-to-integer (or bool) comparisons */
01392                 if (((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
01393                      || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_BOOL))
01394                     && ((OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT)
01395                         || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_BOOL)))
01396                 {
01397                     int32_t a = ((pPmInt_t)TOS1)->val;
01398                     int32_t b = ((pPmInt_t)TOS)->val;
01399 
01400                     switch (t16)
01401                     {
01402                         /* *INDENT-OFF* */
01403                         case COMP_LT: t8 = (int8_t)(a <  b); break;
01404                         case COMP_LE: t8 = (int8_t)(a <= b); break;
01405                         case COMP_EQ: t8 = (int8_t)(a == b); break;
01406                         case COMP_NE: t8 = (int8_t)(a != b); break;
01407                         case COMP_GT: t8 = (int8_t)(a >  b); break;
01408                         case COMP_GE: t8 = (int8_t)(a >= b); break;
01409                         case COMP_IS: t8 = (int8_t)(TOS == TOS1); break;
01410                         case COMP_IS_NOT: t8 = (int8_t)(TOS != TOS1);break;
01411                         case COMP_IN:
01412                         case COMP_NOT_IN:
01413                             PM_RAISE(retval, PM_RET_EX_TYPE);
01414                             break;
01415 
01416                         default:
01417                             /* Other compares are not yet supported */
01418                             PM_RAISE(retval, PM_RET_EX_SYS);
01419                             break;
01420                         /* *INDENT-ON* */
01421                     }
01422                     PM_BREAK_IF_ERROR(retval);
01423                     pobj3 = (t8) ? PM_TRUE : PM_FALSE;
01424                 }
01425 
01426                 /* Handle non-integer comparisons */
01427                 else
01428                 {
01429                     retval = PM_RET_OK;
01430                     switch (t16)
01431                     {
01432                         case COMP_EQ:
01433                         case COMP_NE:
01434                             /* Handle equality for non-int types */
01435                             pobj3 = PM_FALSE;
01436                             t8 = obj_compare(TOS, TOS1);
01437                             if (((t8 == C_SAME) && (t16 == COMP_EQ))
01438                                 || ((t8 == C_DIFFER) && (t16 == COMP_NE)))
01439                             {
01440                                 pobj3 = PM_TRUE;
01441                             }
01442                             break;
01443 
01444                         case COMP_IN:
01445                         case COMP_NOT_IN:
01446                             /* Handle membership comparisons */
01447                             pobj3 = PM_FALSE;
01448                             retval = obj_isIn(TOS, TOS1);
01449                             if (retval == PM_RET_OK)
01450                             {
01451                                 if (t16 == COMP_IN)
01452                                 {
01453                                     pobj3 = PM_TRUE;
01454                                 }
01455                             }
01456                             else if (retval == PM_RET_NO)
01457                             {
01458                                 retval = PM_RET_OK;
01459                                 if (t16 == COMP_NOT_IN)
01460                                 {
01461                                     pobj3 = PM_TRUE;
01462                                 }
01463                             }
01464                             break;
01465 
01466                         case COMP_IS:
01467                             pobj3 = (TOS == TOS1) ? PM_TRUE : PM_FALSE;
01468                             break;
01469 
01470                         case COMP_IS_NOT:
01471                             pobj3 = (TOS != TOS1) ? PM_TRUE : PM_FALSE;
01472                             break;
01473 
01474                         default:
01475                             /* Other comparisons are not implemented */
01476                             PM_RAISE(retval, PM_RET_EX_SYS);
01477                             break;
01478                     }
01479                     PM_BREAK_IF_ERROR(retval);
01480                 }
01481                 PM_SP--;
01482                 TOS = pobj3;
01483                 continue;
01484 
01485             case IMPORT_NAME:
01486                 /* Get name index */
01487                 t16 = GET_ARG();
01488 
01489                 /* Get name String obj */
01490                 pobj1 = PM_FP->fo_func->f_co->co_names->val[t16];
01491 
01492                 /* Pop unused None object */
01493                 PM_SP--;
01494 
01495                 /* Ensure "level" is -1; no support for relative import yet */
01496                 C_ASSERT(obj_compare(TOS, PM_NEGONE) == C_SAME);
01497 
01498                 /* #178: Fix import so modules are reused */
01499                 /* Return the module if found in the modules dict (cache) */
01500                 retval = dict_getItem(PM_PBUILTINS, PM_MD_STR, &pobj3);
01501                 PM_BREAK_IF_ERROR(retval);
01502                 retval = dict_getItem(pobj3, pobj1, &pobj2);
01503                 if (retval == PM_RET_OK)
01504                 {
01505                     TOS = pobj2;
01506                     continue;
01507                 }
01508                 if (retval != PM_RET_EX_KEY)
01509                 {
01510                     break;
01511                 }
01512 
01513                 /* Load module from image */
01514                 retval = mod_import(pobj1, &pobj2);
01515                 PM_BREAK_IF_ERROR(retval);
01516 
01517                 /* #178: Fix import so modules are reused */
01518                 /*
01519                  * Store the module's attrs/globals under the module's name
01520                  * in the global module dict (cache)
01521                  */
01522                 heap_gcPushTempRoot(pobj2, &objid);
01523                 retval = dict_setItem(pobj3, pobj1, pobj2);
01524                 heap_gcPopTempRoot(objid);
01525                 PM_BREAK_IF_ERROR(retval);
01526 
01527                 /* Put Module on top of stack */
01528                 TOS = pobj2;
01529 
01530                 /* Code after here is a duplicate of CALL_FUNCTION */
01531                 /* Make frame object to interpret the module's root code */
01532                 heap_gcPushTempRoot(pobj2, &objid);
01533                 retval = frame_new(pobj2, &pobj3);
01534                 heap_gcPopTempRoot(objid);
01535                 PM_BREAK_IF_ERROR(retval);
01536 
01537                 /* No arguments to pass */
01538 
01539                 /* Keep ref to current frame */
01540                 ((pPmFrame_t)pobj3)->fo_back = PM_FP;
01541 
01542                 /* Handle to have None popped on return */
01543                 ((pPmFrame_t)pobj3)->fo_isImport = (uint8_t)1;
01544 
01545                 /* Set new frame */
01546                 PM_FP = (pPmFrame_t)pobj3;
01547                 continue;
01548 
01549 #ifdef HAVE_IMPORTS
01550             case IMPORT_FROM:
01551                 /* #102: Implement the remaining IMPORT_ bytecodes */
01552                 /* Expect the module on the top of the stack */
01553                 C_ASSERT(OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD);
01554                 pobj1 = TOS;
01555 
01556                 /* Get the name of the object to import */
01557                 t16 = GET_ARG();
01558                 pobj2 = PM_FP->fo_func->f_co->co_names->val[t16];
01559 
01560                 /* Get the object from the module's attributes */
01561                 retval = dict_getItem((pPmObj_t)((pPmFunc_t)pobj1)->f_attrs,
01562                                       pobj2, &pobj3);
01563                 PM_BREAK_IF_ERROR(retval);
01564 
01565                 /* Push the object onto the top of the stack */
01566                 PM_PUSH(pobj3);
01567                 continue;
01568 #endif /* HAVE_IMPORTS */
01569 
01570             case JUMP_FORWARD:
01571                 t16 = GET_ARG();
01572                 PM_IP += t16;
01573                 continue;
01574                 
01575 #ifdef HAVE_PYTHON27
01576             case JUMP_IF_FALSE_OR_POP:
01577                 t16 = GET_ARG();
01578                 if (obj_isFalse(TOS))
01579                 {
01580                     PM_IP = PM_FP->fo_func->f_co->co_codeaddr + t16;
01581                 }
01582                 else
01583                 {
01584                     --PM_SP;
01585                 }
01586                 continue;
01587 
01588             case JUMP_IF_TRUE_OR_POP:
01589                 t16 = GET_ARG();
01590                 if (!obj_isFalse(TOS))
01591                 {
01592                     PM_IP = PM_FP->fo_func->f_co->co_codeaddr + t16;
01593                 }
01594                 else
01595                 {
01596                     --PM_SP;
01597                 }
01598                 continue;
01599 
01600             case POP_JUMP_IF_FALSE:
01601                 t16 = GET_ARG();
01602                 if (obj_isFalse(TOS))
01603                 {
01604                     PM_IP = PM_FP->fo_func->f_co->co_codeaddr + t16;
01605                 }
01606                 --PM_SP;
01607                 continue;
01608 
01609             case POP_JUMP_IF_TRUE:
01610                 t16 = GET_ARG();
01611                 if (!obj_isFalse(TOS))
01612                 {
01613                     PM_IP = PM_FP->fo_func->f_co->co_codeaddr + t16;
01614                 }
01615                 --PM_SP;
01616                 continue;
01617 #else /* HAVE_PYTHON27 */
01618             case JUMP_IF_FALSE:
01619                 t16 = GET_ARG();
01620                 if (obj_isFalse(TOS))
01621                 {
01622                     PM_IP += t16;
01623                 }
01624                 continue;
01625 
01626             case JUMP_IF_TRUE:
01627                 t16 = GET_ARG();
01628                 if (!obj_isFalse(TOS))
01629                 {
01630                     PM_IP += t16;
01631                 }
01632                 continue;
01633 #endif /* HAVE_PYTHON27 */
01634 
01635             case JUMP_ABSOLUTE:
01636             case CONTINUE_LOOP:
01637                 /* Get target offset (bytes) */
01638                 t16 = GET_ARG();
01639 
01640                 /* Jump to base_ip + arg */
01641                 PM_IP = PM_FP->fo_func->f_co->co_codeaddr + t16;
01642                 continue;
01643 
01644             case LOAD_GLOBAL:
01645                 /* Get name */
01646                 t16 = GET_ARG();
01647                 pobj1 = PM_FP->fo_func->f_co->co_names->val[t16];
01648 
01649                 /* Try globals first */
01650                 retval = dict_getItem((pPmObj_t)PM_FP->fo_globals,
01651                                       pobj1, &pobj2);
01652 
01653                 /* If that didn't work, try builtins */
01654                 if (retval == PM_RET_EX_KEY)
01655                 {
01656                     retval = dict_getItem(PM_PBUILTINS, pobj1, &pobj2);
01657 
01658                     /* No such global, raise NameError */
01659                     if (retval == PM_RET_EX_KEY)
01660                     {
01661                         PM_RAISE(retval, PM_RET_EX_NAME);
01662                         break;
01663                     }
01664                 }
01665                 PM_BREAK_IF_ERROR(retval);
01666                 PM_PUSH(pobj2);
01667                 continue;
01668 
01669             case SETUP_LOOP:
01670             {
01671                 uint8_t *pchunk;
01672 
01673                 /* Get block span (bytes) */
01674                 t16 = GET_ARG();
01675 
01676                 /* Create block */
01677                 retval = heap_getChunk(sizeof(PmBlock_t), &pchunk);
01678                 PM_BREAK_IF_ERROR(retval);
01679                 pobj1 = (pPmObj_t)pchunk;
01680                 OBJ_SET_TYPE(pobj1, OBJ_TYPE_BLK);
01681 
01682                 /* Store current stack pointer */
01683                 ((pPmBlock_t)pobj1)->b_sp = PM_SP;
01684 
01685                 /* Default handler is to exit block/loop */
01686                 ((pPmBlock_t)pobj1)->b_handler = PM_IP + t16;
01687                 ((pPmBlock_t)pobj1)->b_type = B_LOOP;
01688 
01689                 /* Insert block into blockstack */
01690                 ((pPmBlock_t)pobj1)->next = PM_FP->fo_blockstack;
01691                 PM_FP->fo_blockstack = (pPmBlock_t)pobj1;
01692                 continue;
01693             }
01694 
01695             case LOAD_FAST:
01696                 t16 = GET_ARG();
01697                 PM_PUSH(PM_FP->fo_locals[t16]);
01698                 continue;
01699 
01700             case STORE_FAST:
01701                 t16 = GET_ARG();
01702                 PM_FP->fo_locals[t16] = PM_POP();
01703                 continue;
01704 
01705 #ifdef HAVE_DEL
01706             case DELETE_FAST:
01707                 t16 = GET_ARG();
01708                 PM_FP->fo_locals[t16] = PM_NONE;
01709                 continue;
01710 #endif /* HAVE_DEL */
01711 
01712 #ifdef HAVE_ASSERT
01713             case RAISE_VARARGS:
01714                 t16 = GET_ARG();
01715 
01716                 /* Only supports taking 1 arg for now */
01717                 if (t16 != 1)
01718                 {
01719                     PM_RAISE(retval, PM_RET_EX_SYS);
01720                     break;
01721                 }
01722 
01723                 /* Load Exception class from builtins */
01724                 retval = dict_getItem(PM_PBUILTINS, PM_EXCEPTION_STR, &pobj2);
01725                 if (retval != PM_RET_OK)
01726                 {
01727                     PM_RAISE(retval, PM_RET_EX_SYS);
01728                     break;
01729                 }
01730 
01731                 /* Raise TypeError if TOS is not an instance of Exception */
01732                 pobj1 = TOS;
01733                 if ((OBJ_GET_TYPE(pobj1) != OBJ_TYPE_CLO)
01734                     || !class_isSubclass(pobj1, pobj2))
01735                 {
01736                     PM_RAISE(retval, PM_RET_EX_TYPE);
01737                     break;
01738                 }
01739 
01740                 /* Push the traceback, parameter and exception object */
01741                 TOS = PM_NONE;
01742                 PM_PUSH(PM_NONE);
01743                 PM_PUSH(pobj1);
01744 
01745                 /* Get the exception's code attr */
01746                 retval = dict_getItem((pPmObj_t)((pPmClass_t)pobj1)->cl_attrs,
01747                                       PM_CODE_STR, &pobj2);
01748                 PM_BREAK_IF_ERROR(retval);
01749 
01750                 /* Raise exception by breaking with retval set to code */
01751                 PM_RAISE(retval, (PmReturn_t)(((pPmInt_t)pobj2)->val & 0xFF));
01752                 break;
01753 #endif /* HAVE_ASSERT */
01754 
01755             case CALL_FUNCTION:
01756                 /* Get num args */
01757                 t16 = GET_ARG();
01758 
01759                 /* Ensure no keyword args */
01760                 if ((t16 & (uint16_t)0xFF00) != 0)
01761                 {
01762                     PM_RAISE(retval, PM_RET_EX_SYS);
01763                     break;
01764                 }
01765 
01766                 /* Get the callable */
01767                 pobj1 = STACK(t16);
01768 
01769                 /* Useless push to get temp-roots stack level used in cleanup */
01770                 heap_gcPushTempRoot(pobj1, &objid);
01771 
01772                 C_DEBUG_PRINT(VERBOSITY_LOW,
01773                     "interpret(), CALL_FUNCTION on <obj type=%d @ %p>\n",
01774                     OBJ_GET_TYPE(pobj1), pobj1);
01775 
01776 #ifdef HAVE_GENERATORS
01777                 /* If the callable is a generator function (can't be native) */
01778                 if ((OBJ_GET_TYPE(pobj1) == OBJ_TYPE_FXN)
01779                     && (OBJ_GET_TYPE(((pPmFunc_t)pobj1)->f_co) == OBJ_TYPE_COB)
01780                     && (((pPmFunc_t)pobj1)->f_co->co_flags & CO_GENERATOR))
01781                 {
01782 #ifdef HAVE_DEFAULTARGS
01783                     /* Num required args := argcount - num default args */
01784                     t8 = ((pPmFunc_t)pobj1)->f_co->co_argcount;
01785                     if (((pPmFunc_t)pobj1)->f_defaultargs != C_NULL)
01786                     {
01787                         t8 -= ((pPmTuple_t)((pPmFunc_t)pobj1)->f_defaultargs)->
01788                             length;
01789                     }
01790 
01791                     /*
01792                      * Raise a TypeError if num args passed
01793                      * is more than allowed or less than required
01794                      */
01795                     if (((t16 & ((uint8_t)0xFF))
01796                          > ((pPmFunc_t)pobj1)->f_co->co_argcount)
01797                         || ((t16 & ((uint8_t)0xFF)) < t8))
01798 #else
01799                     if ((t16 & ((uint8_t)0xFF)) !=
01800                         ((pPmFunc_t)pobj1)->f_co->co_argcount)
01801 #endif /* HAVE_DEFAULTARGS */
01802                     {
01803                         PM_RAISE(retval, PM_RET_EX_TYPE);
01804                         break;
01805                     }
01806 
01807                     /* Collect the function and arguments into a tuple */
01808                     retval = tuple_new(t16 + 1, &pobj2);
01809                     heap_gcPushTempRoot(pobj2, &objid2);
01810                     PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP);
01811                     sli_memcpy((uint8_t *)&((pPmTuple_t)pobj2)->val,
01812                                (uint8_t *)&STACK(t16),
01813                                (t16 + 1) * sizeof(pPmObj_t));
01814 
01815                     /* Remove old args, push func/args tuple as one arg */
01816                     PM_SP -= t16;
01817                     PM_PUSH(pobj2);
01818                     t16 = 1;
01819 
01820                     /* Set pobj1 and stack to create an instance of Generator */
01821                     retval = dict_getItem(PM_PBUILTINS, PM_GENERATOR_STR,
01822                                           &pobj1);
01823                     C_ASSERT(retval == PM_RET_OK);
01824                     STACK(t16) = pobj1;
01825                 }
01826 #endif /* HAVE_GENERATORS */
01827 
01828 #ifdef HAVE_CLASSES
01829                 /* If the callable is a class, create an instance of it */
01830                 if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_CLO)
01831                 {
01832                     /* This marks that the original callable was a class */
01833                     bc = 0;
01834 
01835                     /* Replace class with new instance */
01836                     retval = class_instantiate(pobj1, &pobj2);
01837                     heap_gcPushTempRoot(pobj2, &objid2);
01838                     STACK(t16) = pobj2;
01839 
01840                     /* If __init__ does not exist */
01841                     pobj3 = C_NULL;
01842                     retval = class_getAttr(pobj1, PM_INIT_STR, &pobj3);
01843                     if (retval == PM_RET_EX_KEY)
01844                     {
01845                         /* Raise TypeError if there are args */
01846                         if (t16 > 0)
01847                         {
01848                             PM_RAISE(retval, PM_RET_EX_TYPE);
01849                             goto CALL_FUNC_CLEANUP;
01850                         }
01851 
01852                         /* Otherwise, continue with instance */
01853                         heap_gcPopTempRoot(objid);
01854                         continue;
01855                     }
01856                     else if (retval != PM_RET_OK)
01857                     {
01858                         PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP);
01859                     }
01860 
01861                     /* Slide the arguments up 1 slot in the stack */
01862                     PM_SP++;
01863                     for (t8 = 0; t8 < t16; t8++)
01864                     {
01865                         STACK(t8) = STACK(t8 + 1);
01866                     }
01867 
01868                     /* Convert __init__ to method, insert it as the callable */
01869                     retval = class_method(pobj2, pobj3, &pobj1);
01870                     PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP);
01871                     heap_gcPushTempRoot(pobj2, &objid2);
01872                     STACK(t16) = pobj1;
01873                     /* Fall through to call the method */
01874                 }
01875 
01876                 if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_MTH)
01877                 {
01878                     /* Set the method's func to be the callable */
01879                     STACK(t16) = (pPmObj_t)((pPmMethod_t)pobj1)->m_func;
01880 
01881                     /* Slide the arguments up 1 slot in the stack */
01882                     PM_SP++;
01883                     for (t8 = 0; t8 < t16; t8++)
01884                     {
01885                         STACK(t8) = STACK(t8 + 1);
01886                     }
01887 
01888                     /* Insert instance as "self" arg to the method */
01889                     STACK(t16++) = (pPmObj_t)((pPmMethod_t)pobj1)->m_instance;
01890 
01891                     /* Refresh the callable */
01892                     pobj1 = (pPmObj_t)((pPmMethod_t)pobj1)->m_func;
01893                 }
01894 #endif /* HAVE_CLASSES */
01895 
01896 #ifdef HAVE_GENERATORS
01897 CALL_FUNC_FOR_ITER:
01898 #endif /* HAVE_GENERATORS */
01899                 /* Raise a TypeError if object is not callable */
01900                 if (OBJ_GET_TYPE(pobj1) != OBJ_TYPE_FXN)
01901                 {
01902                     PM_RAISE(retval, PM_RET_EX_TYPE);
01903                     goto CALL_FUNC_CLEANUP;
01904                 }
01905 
01906                 /* If it is a regular func (not native) */
01907                 if (OBJ_GET_TYPE(((pPmFunc_t)pobj1)->f_co) == OBJ_TYPE_COB)
01908                 {
01909                     /*
01910                      * #132 Raise TypeError if num args does not match the
01911                      * code object's expected argcount
01912                      */
01913 
01914 #ifdef HAVE_DEFAULTARGS
01915                     /* Num required args := argcount - num default args */
01916                     t8 = ((pPmFunc_t)pobj1)->f_co->co_argcount;
01917                     if (((pPmFunc_t)pobj1)->f_defaultargs != C_NULL)
01918                     {
01919                         t8 -= ((pPmTuple_t)((pPmFunc_t)pobj1)->f_defaultargs)->
01920                             length;
01921                     }
01922 
01923                     /*
01924                      * Raise a TypeError if num args passed
01925                      * is more than allowed or less than required
01926                      */
01927                     if (((t16 & ((uint8_t)0xFF))
01928                          > ((pPmFunc_t)pobj1)->f_co->co_argcount)
01929                         || ((t16 & ((uint8_t)0xFF)) < t8))
01930 #else
01931                     if ((t16 & ((uint8_t)0xFF)) !=
01932                         ((pPmFunc_t)pobj1)->f_co->co_argcount)
01933 #endif /* HAVE_DEFAULTARGS */
01934                     {
01935                         PM_RAISE(retval, PM_RET_EX_TYPE);
01936                         break;
01937                     }
01938 
01939                     /* Make frame object to run the func object */
01940                     retval = frame_new(pobj1, &pobj2);
01941                     heap_gcPushTempRoot(pobj2, &objid2);
01942                     PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP);
01943 
01944 #ifdef HAVE_CLASSES
01945                     /*
01946                      * If the original callable was a class, indicate that
01947                      * the frame is running the initializer so that
01948                      * its return object is checked for None and ignored.
01949                      */
01950                     if (bc == 0)
01951                     {
01952                         ((pPmFrame_t)pobj2)->fo_isInit = C_TRUE;
01953                     }
01954 #endif /* HAVE_CLASSES */
01955 
01956 #ifdef HAVE_DEFAULTARGS
01957                     /* If this func has default arguments, put them in place */
01958                     if (((pPmFunc_t)pobj1)->f_defaultargs != C_NULL)
01959                     {
01960                         int8_t i = 0;
01961 
01962                         /* Copy default args into the new frame's locals */
01963                         for ( /* t8 set above */ ;
01964                              t8 < ((pPmFunc_t)pobj1)->f_co->co_argcount; t8++)
01965                         {
01966                             ((pPmFrame_t)pobj2)->fo_locals[t8] =
01967                                 ((pPmTuple_t)((pPmFunc_t)pobj1)->
01968                                  f_defaultargs)->val[i++];
01969                         }
01970                     }
01971 #endif /* HAVE_DEFAULTARGS */
01972 
01973                     /* Pass args to new frame */
01974                     while (--t16 >= 0)
01975                     {
01976                         /*
01977                          * Pop args from stack right to left,
01978                          * since args are pushed left to right,
01979                          */
01980                         ((pPmFrame_t)pobj2)->fo_locals[t16] = PM_POP();
01981                     }
01982 
01983 #ifdef HAVE_CLOSURES
01984                     /* #256: Add support for closures */
01985                     /* Copy arguments that become cellvars */
01986                     if (((pPmFunc_t)pobj1)->f_co->co_cellvars != C_NULL)
01987                     {
01988                         for (t8 = 0;
01989                              t8 < ((pPmFunc_t)pobj1)->f_co->co_cellvars->length;
01990                              t8++)
01991                         {
01992                             if (((pPmInt_t)((pPmFunc_t)pobj1)->
01993                                 f_co->co_cellvars->val[t8])->val >= 0)
01994                             {
01995                                 ((pPmFrame_t)pobj2)->fo_locals[
01996                                     ((pPmFunc_t)pobj1)->f_co->co_nlocals + t8] =
01997                                     ((pPmFrame_t)pobj2)->fo_locals[
01998                                         ((pPmInt_t)(((pPmFunc_t)pobj1)->
01999                                             f_co->co_cellvars->val[t8]))->val
02000                                     ];
02001                             }
02002                         }
02003                     }
02004 
02005                     /* Fill frame's freevars with references from closure */
02006                     for (t8 = 0;
02007                          t8 < ((pPmFunc_t)pobj1)->f_co->co_nfreevars;
02008                          t8++)
02009                     {
02010                         C_ASSERT(((pPmFunc_t)pobj1)->f_closure != C_NULL);
02011                         ((pPmFrame_t)pobj2)->fo_locals[
02012                             ((pPmFunc_t)pobj1)->f_co->co_nlocals
02013                             + ((((pPmFunc_t)pobj1)->f_co->co_cellvars == C_NULL) ? 0 : ((pPmFunc_t)pobj1)->f_co->co_cellvars->length)
02014                             + t8] = ((pPmFunc_t)pobj1)->f_closure->val[t8];
02015                     }
02016 #endif /* HAVE_CLOSURES */
02017 
02018                     /* Pop func obj */
02019                     pobj3 = PM_POP();
02020 
02021                     /* Keep ref to current frame */
02022                     ((pPmFrame_t)pobj2)->fo_back = PM_FP;
02023 
02024                     /* Set new frame */
02025                     PM_FP = (pPmFrame_t)pobj2;
02026                 }
02027 
02028                 /* If it's native func */
02029                 else if (OBJ_GET_TYPE(((pPmFunc_t)pobj1)->f_co) ==
02030                          OBJ_TYPE_NOB)
02031                 {
02032                     /* Set number of locals (arguments) */
02033                     gVmGlobal.nativeframe.nf_numlocals = (uint8_t)t16;
02034 
02035                     /* Pop args from stack */
02036                     while (--t16 >= 0)
02037                     {
02038                         gVmGlobal.nativeframe.nf_locals[t16] = PM_POP();
02039                     }
02040 
02041                     /* Set flag, so the GC knows a native session is active */
02042                     gVmGlobal.nativeframe.nf_active = C_TRUE;
02043 
02044 #ifdef HAVE_GC
02045                     /* If the heap is low on memory, run the GC */
02046                     if (heap_getAvail () < HEAP_GC_NF_THRESHOLD)
02047                     {
02048                         retval = heap_gcRun();
02049                         PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP);
02050                     }
02051 #endif /* HAVE_GC */
02052 
02053                     /* Pop the function object */
02054                     PM_SP--;
02055 
02056                     /* Get native function index */
02057                     pobj2 = (pPmObj_t)((pPmFunc_t)pobj1)->f_co;
02058                     t16 = ((pPmNo_t)pobj2)->no_funcindx;
02059 
02060                     /*
02061                      * CALL NATIVE FXN: pass caller's frame and numargs
02062                      */
02063                     /* Positive index is a stdlib func */
02064                     if (t16 >= 0)
02065                     {
02066                         retval = std_nat_fxn_table[t16] (&PM_FP);
02067                     }
02068 
02069                     /* Negative index is a usrlib func */
02070                     else
02071                     {
02072                         retval = usr_nat_fxn_table[-t16] (&PM_FP);
02073                     }
02074 
02075                     /*
02076                      * RETURN FROM NATIVE FXN
02077                      */
02078 
02079                     /* Clear flag, so frame will not be marked by the GC */
02080                     gVmGlobal.nativeframe.nf_active = C_FALSE;
02081 
02082 #ifdef HAVE_CLASSES
02083                     /* If class's __init__ called, do not push a return obj */
02084                     if (bc == 0)
02085                     {
02086                         /* Raise TypeError if returned obj was not None */
02087                         if ((retval == PM_RET_OK)
02088                             && (gVmGlobal.nativeframe.nf_stack != PM_NONE))
02089                         {
02090                             PM_RAISE(retval, PM_RET_EX_TYPE);
02091                             goto CALL_FUNC_CLEANUP;
02092                         }
02093                     }
02094                     else
02095 #endif /* HAVE_CLASSES */
02096 
02097                     /* If the frame pointer was switched, do nothing to TOS */
02098                     if (retval == PM_RET_FRAME_SWITCH)
02099                     {
02100                         retval = PM_RET_OK;
02101                     }
02102 
02103                     /* Otherwise, return the result from the native function */
02104                     else
02105                     {
02106                         PM_PUSH(gVmGlobal.nativeframe.nf_stack);
02107                     }
02108                 }
02109 CALL_FUNC_CLEANUP:
02110                 heap_gcPopTempRoot(objid);
02111                 PM_BREAK_IF_ERROR(retval);
02112                 continue;
02113 
02114             case MAKE_FUNCTION:
02115                 /* Get num default args to fxn */
02116                 t16 = GET_ARG();
02117 
02118                 /*
02119                  * The current frame's globals become the function object's
02120                  * globals.  The current frame is the container object
02121                  * of this new function object
02122                  */
02123                 retval = func_new(TOS, (pPmObj_t)PM_FP->fo_globals, &pobj2);
02124                 PM_BREAK_IF_ERROR(retval);
02125 
02126                 /* Put any default args in a tuple */
02127                 if (t16 > 0)
02128                 {
02129 
02130 #ifdef HAVE_DEFAULTARGS
02131                     heap_gcPushTempRoot(pobj2, &objid);
02132                     retval = tuple_new(t16, &pobj3);
02133                     heap_gcPopTempRoot(objid);
02134                     PM_BREAK_IF_ERROR(retval);
02135                     PM_SP--;
02136                     while (--t16 >= 0)
02137                     {
02138                         ((pPmTuple_t)pobj3)->val[t16] = PM_POP();
02139                     }
02140 
02141                     /* Set func's default args */
02142                     ((pPmFunc_t)pobj2)->f_defaultargs = (pPmTuple_t)pobj3;
02143 #else
02144                     /* Default arguments not configured in pmfeatures.h */
02145                     PM_RAISE(retval, PM_RET_EX_SYS);
02146                     break;
02147 #endif /* HAVE_DEFAULTARGS */
02148 
02149                 }
02150                 else
02151                 {
02152                     PM_SP--;
02153                 }
02154 
02155                 /* Push func obj */
02156                 PM_PUSH(pobj2);
02157                 continue;
02158 
02159 #ifdef HAVE_CLOSURES
02160             case MAKE_CLOSURE:
02161                 /* Get number of default args */
02162                 t16 = GET_ARG();
02163                 retval = func_new(TOS, (pPmObj_t)PM_FP->fo_globals, &pobj2);
02164                 PM_BREAK_IF_ERROR(retval);
02165 
02166                 /* Set closure of the new function */
02167                 ((pPmFunc_t)pobj2)->f_closure = (pPmTuple_t)TOS1;
02168                 PM_SP -= 2;
02169 
02170                 /* Collect any default arguments into tuple */
02171                 if (t16 > 0)
02172                 {
02173                     heap_gcPushTempRoot(pobj2, &objid);
02174                     retval = tuple_new(t16, &pobj3);
02175                     heap_gcPopTempRoot(objid);
02176                     PM_BREAK_IF_ERROR(retval);
02177 
02178                     while (--t16 >= 0)
02179                     {
02180                         ((pPmTuple_t)pobj3)->val[t16] = PM_POP();
02181                     }
02182                     ((pPmFunc_t)pobj2)->f_defaultargs = (pPmTuple_t)pobj3;
02183                 }
02184 
02185                 /* Push new func with closure */
02186                 PM_PUSH(pobj2);
02187                 continue;
02188 
02189             case LOAD_CLOSURE:
02190             case LOAD_DEREF:
02191                 /* Loads the i'th cell of free variable storage onto TOS */
02192                 t16 = GET_ARG();
02193                 pobj1 = PM_FP->fo_locals[PM_FP->fo_func->f_co->co_nlocals + t16];
02194                 if (pobj1 == C_NULL)
02195                 {
02196                     PM_RAISE(retval, PM_RET_EX_SYS);
02197                     break;
02198                 }
02199                 PM_PUSH(pobj1);
02200                 continue;
02201 
02202             case STORE_DEREF:
02203                 /* Stores TOS into the i'th cell of free variable storage */
02204                 t16 = GET_ARG();
02205                 PM_FP->fo_locals[PM_FP->fo_func->f_co->co_nlocals + t16] = PM_POP();
02206                 continue;
02207 #endif /* HAVE_CLOSURES */
02208 
02209 
02210             default:
02211 #ifdef HAVE_PYTHON27
02212                 printf("SystemError unimplemented opcode %02x\n", bc);
02213                 C_ASSERT(0);
02214 #endif
02215                 /* SystemError, unknown or unimplemented opcode */
02216                 PM_RAISE(retval, PM_RET_EX_SYS);
02217                 break;
02218         }
02219 
02220 #ifdef HAVE_GENERATORS
02221         /* If got a StopIteration exception, check for a B_LOOP block */
02222         if (retval == PM_RET_EX_STOP)
02223         {
02224             pobj1 = (pPmObj_t)PM_FP;
02225             while ((retval == PM_RET_EX_STOP) && (pobj1 != C_NULL))
02226             {
02227                 pobj2 = (pPmObj_t)((pPmFrame_t)pobj1)->fo_blockstack;
02228                 while ((retval == PM_RET_EX_STOP) && (pobj2 != C_NULL))
02229                 {
02230                     if (((pPmBlock_t)pobj2)->b_type == B_LOOP)
02231                     {
02232                         /* Resume execution where the block handler says */
02233                         /* Set PM_FP first, so PM_SP and PM_IP are set in the frame */
02234                         PM_FP = (pPmFrame_t)pobj1;
02235                         PM_SP = ((pPmBlock_t)pobj2)->b_sp;
02236                         PM_IP = ((pPmBlock_t)pobj2)->b_handler;
02237                         ((pPmFrame_t)pobj1)->fo_blockstack =
02238                             ((pPmFrame_t)pobj1)->fo_blockstack->next;
02239                         retval = PM_RET_OK;
02240                         break;
02241                     }
02242 
02243                     pobj2 = (pPmObj_t)((pPmBlock_t)pobj2)->next;
02244                 }
02245                 pobj1 = (pPmObj_t)((pPmFrame_t)pobj1)->fo_back;
02246             }
02247             if (retval == PM_RET_OK)
02248             {
02249                 continue;
02250             }
02251         }
02252 #endif /* HAVE_GENERATORS */
02253 
02254         /*
02255          * If execution reaches this point, it is because
02256          * a return value (from above) is not OK or we should exit the thread
02257          * (return of the function). In any case, remove the
02258          * current thread and reschedule.
02259          */
02260         PM_REPORT_IF_ERROR(retval);
02261 
02262         /* If this is the last thread, return the error code */
02263         if ((gVmGlobal.threadList->length <= 1) && (retval != PM_RET_OK))
02264         {
02265             break;
02266         }
02267 
02268         retval = list_remove((pPmObj_t)gVmGlobal.threadList,
02269                              (pPmObj_t)gVmGlobal.pthread);
02270         gVmGlobal.pthread = C_NULL;
02271         PM_BREAK_IF_ERROR(retval);
02272 
02273         retval = interp_reschedule();
02274         PM_BREAK_IF_ERROR(retval);
02275     }
02276 
02277     return retval;
02278 }
02279 
02280 
02281 PmReturn_t
02282 interp_reschedule(void)
02283 {
02284     PmReturn_t retval = PM_RET_OK;
02285     static uint8_t threadIndex = (uint8_t)0;
02286     pPmObj_t pobj;
02287 
02288     /* If there are no threads in the runnable list, null the active thread */
02289     if (gVmGlobal.threadList->length == 0)
02290     {
02291         gVmGlobal.pthread = C_NULL;
02292     }
02293 
02294     /* Otherwise, get the next thread in the list (round robin) */
02295     else
02296     {
02297         if (++threadIndex >= gVmGlobal.threadList->length)
02298         {
02299             threadIndex = (uint8_t)0;
02300         }
02301         retval = list_getItem((pPmObj_t)gVmGlobal.threadList, threadIndex,
02302                               &pobj);
02303         gVmGlobal.pthread = (pPmThread_t)pobj;
02304         PM_RETURN_IF_ERROR(retval);
02305     }
02306 
02307     /* Clear flag to indicate a reschedule has occurred */
02308     interp_setRescheduleFlag(0);
02309     return retval;
02310 }
02311 
02312 
02313 PmReturn_t
02314 interp_addThread(pPmFunc_t pfunc)
02315 {
02316     PmReturn_t retval;
02317     pPmObj_t pframe;
02318     pPmObj_t pthread;
02319     uint8_t objid1, objid2;
02320 
02321     /* Create a frame for the func */
02322     retval = frame_new((pPmObj_t)pfunc, &pframe);
02323     PM_RETURN_IF_ERROR(retval);
02324 
02325     /* Create a thread with this new frame */
02326     heap_gcPushTempRoot(pframe, &objid1);
02327     retval = thread_new(pframe, &pthread);
02328     if (retval != PM_RET_OK)
02329     {
02330         heap_gcPopTempRoot(objid1);
02331         return retval;
02332     }
02333 
02334     /* Add thread to end of list */
02335     heap_gcPushTempRoot(pthread, &objid2);
02336     retval = list_append((pPmObj_t)gVmGlobal.threadList, pthread);
02337     heap_gcPopTempRoot(objid1);
02338     return retval;
02339 }
02340 
02341 
02342 void
02343 interp_setRescheduleFlag(uint8_t boolean)
02344 {
02345     gVmGlobal.reschedule = boolean;
02346 }