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