interp.c

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

Generated on Mon Oct 18 07:40:47 2010 for Python-on-a-chip by  doxygen 1.5.9