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