Embed:
(wiki syntax)
Show/hide line numbers
interp.c
Go to the documentation of this file.
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