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