Example #1
0
static size_t 
_co_tree_change_length(co_obj_t *tree, const int delta)
{ 
  if(CO_TYPE(tree) == _tree16)
  {
    ((co_tree16_t *)tree)->_len += delta;
    return (size_t)(((co_tree16_t *)tree)->_len);
  } else if(CO_TYPE(tree) == _tree32) {
    ((co_tree32_t *)tree)->_len += delta;
    return (size_t)(((co_tree32_t *)tree)->_len);
  }
  ERROR("Not a tree object.");
  return -1;
}
Example #2
0
int
co_response_get_int(co_obj_t *response, signed long *output, const char *key, const size_t klen) 
{
  co_obj_t *obj = co_response_get(response, key, klen);
  CHECK(obj != NULL, "Response value %s does not exist.", key);
  switch(CO_TYPE(obj))
  {
    case _int8:
      *output = (unsigned long)(((co_int8_t *)obj)->data);
      break;
    case _int16:
      *output = (unsigned long)(((co_int16_t *)obj)->data);
      break;
    case _int32:
      *output = (unsigned long)(((co_int32_t *)obj)->data);
      break;
    case _int64:
      *output = (unsigned long)(((co_int64_t *)obj)->data);
      break;
    default:
      SENTINEL("Not an unsigned integer.");
      break;
  }
  return 1;

error:
  return 0;
}
Example #3
0
size_t
co_tree_raw(char *output, const size_t olen, const co_obj_t *tree)
{
  char *out = output;
  size_t written = 0;
  switch(CO_TYPE(tree))
  {
    case _tree16:
      memmove(out, &(tree->_type), sizeof(tree->_type));
      out += sizeof(tree->_type);
      written += sizeof(tree->_type);
      memmove(out, &(((co_tree16_t *)tree)->_len), sizeof(((co_tree16_t *)tree)->_len));
      out += sizeof(((co_tree16_t *)tree)->_len);
      written += sizeof(((co_tree16_t *)tree)->_len);
      break;
    case _tree32:
      memmove(out, &(tree->_type), sizeof(tree->_type));
      out += sizeof(tree->_type);
      written += sizeof(tree->_type);
      memmove(out, &(((co_tree32_t *)tree)->_len), sizeof(((co_tree32_t *)tree)->_len));
      out += sizeof(((co_tree32_t *)tree)->_len);
      written += sizeof(((co_tree32_t *)tree)->_len);
      break;
    default:
      SENTINEL("Not a tree object.");
      break;
  }
  
  _co_tree_raw_r(&out, &olen, &written, co_tree_root(tree));
  DEBUG("Tree bytes written: %d", (int)written);
  return written;
error:
  return -1;
}
Example #4
0
static int
_co_node_set_uint(_treenode_t *n, const unsigned long value)
{
  CHECK(n != NULL, "Invalid node supplied.");
  switch(CO_TYPE(n->value))
  {
    case _uint8:
      (((co_uint8_t *)(n->value))->data) = value;
      break;
    case _uint16:
      (((co_uint16_t *)(n->value))->data) = value;
      break;
    case _uint32:
      (((co_uint32_t *)(n->value))->data) = value;
      break;
    case _uint64:
      (((co_uint64_t *)(n->value))->data) = value;
      break;
    default:
      SENTINEL("Specified object is not a unsigned integer.");
      break;
  }
  return 1;
error:
  return 0;
}
Example #5
0
static int
_co_node_set_float(_treenode_t *n, const double value)
{
  CHECK(n != NULL, "Invalid node supplied.");
  if(CO_TYPE(n->value) == _float32)
  {
    (((co_float32_t *)(n->value))->data) = value;
  } 
  else if(CO_TYPE(n->value) == _float64) 
  {
    (((co_float64_t *)(n->value))->data) = value;
  }
  else ERROR("Specified object is not a floating-point value.");

  return 1;
error:
  return 0;
}
Example #6
0
_treenode_t *
co_tree_root(const co_obj_t *tree)
{
  CHECK_MEM(tree);
  _treenode_t *n = NULL;
  if(CO_TYPE(tree) == _tree16)
  {
    n = ((co_tree16_t *)tree)->root;
  } 
  else if(CO_TYPE(tree) == _tree32) 
  {
    n = ((co_tree32_t *)tree)->root;
  }
  else SENTINEL("Specified object is not a tree.");

  return n;
error:
  return NULL;
}
Example #7
0
co_obj_t *
co_tree_delete(co_obj_t *root, const char *key, const size_t klen)
{
  co_obj_t *value = NULL;
  if(CO_TYPE(root) == _tree16)
  {
    ((co_tree16_t *)root)->root = _co_tree_delete_r(((co_tree16_t *)root)->root, \
      ((co_tree16_t *)root)->root, key, klen, &value);
  } 
  else if(CO_TYPE(root) == _tree32) 
  {
    ((co_tree32_t *)root)->root = _co_tree_delete_r(((co_tree32_t *)root)->root, \
      ((co_tree32_t *)root)->root, key, klen, &value);
  }

  CHECK(value != NULL, "Failed to delete value.");
  CHECK(_co_tree_decrement(root), "Failed to decrement value.");
  return value;
error:
  return NULL;
}
Example #8
0
static int 
_co_tree_insert(co_obj_t *root, const char *key, const size_t klen, co_obj_t *value)
{
  _treenode_t *n = NULL;
  if(CO_TYPE(root) == _tree16)
  {
    ((co_tree16_t *)root)->root = _co_tree_insert_r(((co_tree16_t *)root)->root, \
      ((co_tree16_t *)root)->root, key, klen, key, klen, value);
    n = ((co_tree16_t *)root)->root;
  } 
  else if(CO_TYPE(root) == _tree32) 
  {
    ((co_tree32_t *)root)->root = _co_tree_insert_r(((co_tree32_t *)root)->root, \
      ((co_tree32_t *)root)->root, key, klen, key, klen, value);
    n = ((co_tree32_t *)root)->root;
  }

  CHECK(n != NULL, "Failed to insert value.");
  CHECK(_co_tree_increment(root), "Failed to increment value.");
  return 1;
error:
  return 0;
}
Example #9
0
int 
co_tree_process(co_obj_t *tree, const co_iter_t iter, void *context)
{
  switch(CO_TYPE(tree))
  {
    case _tree16:
      _co_tree_process_r(tree, ((co_tree16_t *)tree)->root, iter, context);
      break;
    case _tree32:
      _co_tree_process_r(tree, ((co_tree32_t *)tree)->root, iter, context);
      break;
    default:
      SENTINEL("Object is not a tree.");
      break;
  }
  return 1;
error:
  return 0;
}
Example #10
0
static int
_co_node_set_str(_treenode_t *n, const char *value, const size_t vlen)
{
  CHECK(n != NULL, "Invalid node supplied.");
  CHECK(n->value != NULL, "Invalid node supplied.");
  switch(CO_TYPE(n->value))
  {
    case _str8:
      CHECK(vlen <= UINT8_MAX, "Value too large for type str8.");
      if(vlen != (((co_str8_t *)(n->value))->_len))
      {
        n->value = h_realloc(n->value, (size_t)(vlen + sizeof(co_str8_t) - 1));
      }
      CHECK_MEM(memmove((((co_str8_t *)(n->value))->data), value, vlen));
      (((co_str8_t *)(n->value))->_len) = (uint8_t)vlen;
      break;
    case _str16:
      CHECK(vlen <= UINT16_MAX, "Value too large for type str16.");
      if(vlen != (((co_str16_t *)(n->value))->_len))
      {
        n->value = h_realloc(n->value, (size_t)(vlen + sizeof(co_str16_t) - 1));
      }
      CHECK_MEM(memmove((((co_str16_t *)(n->value))->data), value, vlen));
      (((co_str16_t *)(n->value))->_len) = (uint16_t)vlen;
      break;
    case _str32:
      CHECK(vlen <= UINT32_MAX, "Value too large for type str32.");
      if(vlen != (((co_str32_t *)(n->value))->_len))
      {
        n->value = h_realloc(n->value, (size_t)(vlen + sizeof(co_str32_t) - 1));
      }
      CHECK_MEM(memmove((((co_str32_t *)(n->value))->data), value, vlen));
      (((co_str32_t *)(n->value))->_len) = (uint32_t)vlen;
      break;
    default:
      SENTINEL("Specified object is not a string.");
      break;
  }

  return 1;
error:
  return 0;
}
Example #11
0
int
co_response_get_bool(co_obj_t *response, bool *output, const char *key, const size_t klen) {
  co_obj_t *obj = co_response_get(response, key, klen);
  CHECK(obj != NULL, "Response value %s does not exist.", key);
  switch(CO_TYPE(obj))
  {
    case _false:
      *output = false;
      break;
    case _true:
      *output = true;
      break;
    default:
      SENTINEL("Not a boolean.");
      break;
  }
  return 1;
  
  error:
  return 0;
}
Example #12
0
File: vm.c Project: talkspoon/cobj
/*
 * Evaluate a function object into a object.
 */
COObject *
vm_eval(COObject *func, COObject *globals)
{
#define JUMPBY(offset)  next_code += offset
#define JUMPTO(offset)  next_code = first_code + offset
#define NEXTOP()        (*next_code++)
#define NEXTARG()       (next_code += 2, (next_code[-1]<<8) + next_code[-2])
#define GETITEM(v, i)   COTuple_GET_ITEM((COTupleObject *)(v), i)
#define GETLOCAL(i)     (fastlocals[i])
#define SETLOCAL(i, v)                  \
    do {                                \
        COObject *tmp = GETLOCAL(i);    \
        GETLOCAL(i) = v;                \
        CO_XDECREF(tmp);                \
    } while (0);
#define PUSH(o)         (*stack_top++ = (o))
#define POP()           (*--stack_top)
#define TOP()           (stack_top[-1])
#define SET_TOP(o)      (stack_top[-1] = (o))
#define SECOND()        (stack_top[-2])
#define THIRD()         (stack_top[-3])
#define FOURTH()        (stack_top[-4])
#define PEEK(n)         (stack_top[-(n)])
#define STACK_ADJ(n)    (stack_top += n)
#define STACK_LEVEL()   ((int)(stack_top - TS(frame)->f_stack))
#define UNWIND_BLOCK(b) \
    do { \
        while (STACK_LEVEL() > (b)->fb_level) { \
            COObject *o = POP(); \
            CO_XDECREF(o); \
        } \
    } while (0)

    COCodeObject *code;
    COObject *names;
    COObject *consts;
    COObject *localnames;
    COObject *funcargs = COList_New(0);

    COObject **fastlocals;
    COObject **stack_top;       /* Stack top, points to next free slot in stack */

    unsigned char *next_code;
    unsigned char *first_code;
    unsigned char opcode;       /* Current opcode */
    int oparg;                  /* Current opcode argument, if any */
    COObject *x;                /* Result object -- NULL if error */
    COObject *o1, *o2, *o3;     /* Temporary objects popped of stack */
    int status;                 /* VM status */
    int err;                    /* C function error code */
    status = STATUS_NONE;

    TS(frame) =
        (COFrameObject *)COFrame_New((COObject *)TS(frame), func, globals);

new_frame:                     /* reentry point when function call/return */
    code = (COCodeObject *)((COFunctionObject *)TS(frame)->f_func)->func_code;
    stack_top = TS(frame)->f_stacktop;
    names = code->co_names;
    localnames = code->co_localnames;
    consts = code->co_consts;
    first_code = (unsigned char *)COBytes_AsString(code->co_code);
    next_code = first_code + TS(frame)->f_lasti;
    fastlocals = TS(frame)->f_extraplus;

    /* Parse arguments. */
    if (COList_GET_SIZE(funcargs)) {
        // check arguments count
        if (code->co_argcount != COList_GET_SIZE(funcargs)) {
            COErr_Format(COException_ValueError,
                         "takes exactly %d arguments (%d given)",
                         code->co_argcount, COList_Size(funcargs));
            status = STATUS_EXCEPTION;
            goto fast_end;
        }
        size_t n = COList_Size(funcargs);
        for (int i = 0; i < n; i++) {
            x = COList_GetItem(funcargs, 0);
            CO_INCREF(x);
            SETLOCAL(n - i - 1, x);
            COList_DelItem(funcargs, 0);
        }
    }

    for (;;) {
        opcode = NEXTOP();
        switch (opcode) {
        case OP_BINARY_ADD:
            o1 = POP();
            o2 = TOP();
            if (COStr_Check(o1) && COStr_Check(o2)) {
                COStr_Concat(&o2, o1);
                x = o2;
                goto skip_decref_o2;
            } else {
                x = COInt_Type.tp_int_interface->int_add(o1, o2);
            }
            CO_DECREF(o2);
skip_decref_o2:
            CO_DECREF(o1);
            SET_TOP(x);
            if (!x) {
                status = STATUS_EXCEPTION;
                goto fast_end;
            }
            break;
        case OP_BINARY_SUB:
            o1 = POP();
            o2 = TOP();
            x = COInt_Type.tp_int_interface->int_sub(o2, o1);
            CO_DECREF(o1);
            CO_DECREF(o2);
            SET_TOP(x);
            break;
        case OP_BINARY_MUL:
            o1 = POP();
            o2 = TOP();
            x = COInt_Type.tp_int_interface->int_mul(o2, o1);
            CO_DECREF(o1);
            CO_DECREF(o2);
            SET_TOP(x);
            break;
        case OP_BINARY_DIV:
            o1 = POP();
            o2 = TOP();
            x = COInt_Type.tp_int_interface->int_div(o2, o1);
            CO_DECREF(o1);
            CO_DECREF(o2);
            SET_TOP(x);
            break;
        case OP_BINARY_MOD:
            o1 = POP();
            o2 = TOP();
            x = COInt_Type.tp_int_interface->int_mod(o2, o1);
            CO_DECREF(o1);
            CO_DECREF(o2);
            SET_TOP(x);
            break;
        case OP_BINARY_SL:
            o1 = POP();
            o2 = TOP();
            x = COInt_Type.tp_int_interface->int_lshift(o2, o1);
            CO_DECREF(o1);
            CO_DECREF(o2);
            SET_TOP(x);
            break;
        case OP_BINARY_SR:
            o1 = POP();
            o2 = TOP();
            x = COInt_Type.tp_int_interface->int_rshift(o2, o1);
            CO_DECREF(o1);
            CO_DECREF(o2);
            SET_TOP(x);
            break;
        case OP_BINARY_SUBSCRIPT:
            o1 = POP();
            o2 = TOP();
            if (!CO_TYPE(o2)->tp_mapping_interface) {
                COErr_Format(COException_TypeError,
                             "'%.200s' object is not subscriptable",
                             CO_TYPE(o2)->tp_name);
                status = STATUS_EXCEPTION;
            } else {
                x = CO_TYPE(o2)->tp_mapping_interface->mp_subscript(o2, o1);
                if (!x) {
                    status = STATUS_EXCEPTION;
                    goto fast_end;
                }
            }
            CO_DECREF(o1);
            CO_DECREF(o2);
            SET_TOP(x);
            break;
        case OP_CMP:
            o1 = POP();
            o2 = TOP();
            oparg = NEXTARG();
            x = vm_cmp(oparg, o1, o2);
            if (!x) {
                status = STATUS_EXCEPTION;
                goto fast_end;
            }
            CO_DECREF(o1);
            CO_DECREF(o2);
            SET_TOP(x);
            break;
        case OP_UNARY_NEGATE:
            o1 = TOP();
            x = COInt_Type.tp_int_interface->int_neg(o1);
            CO_DECREF(o1);
            SET_TOP(x);
            break;
        case OP_UNARY_INVERT:
            o1 = TOP();
            x = COInt_Type.tp_int_interface->int_invert(o1);
            CO_DECREF(o1);
            SET_TOP(x);
            break;
        case OP_LOAD_LOCAL:
            oparg = NEXTARG();
            x = GETLOCAL(oparg);
            CO_INCREF(x);
            PUSH(x);
            break;
        case OP_LOAD_NAME:
            oparg = NEXTARG();
            o1 = GETITEM(names, oparg);
            x = COObject_get(o1);
            if (!x) {
                COErr_Format(COException_NameError, "name '%s' is not defined",
                             COStr_AsString(o1));
                status = STATUS_EXCEPTION;
                goto fast_end;
            }
            CO_INCREF(x);
            PUSH(x);
            break;
        case OP_LOAD_UPVAL:
            oparg = NEXTARG();
            o1 = COTuple_GET_ITEM(((COFunctionObject *)func)->func_upvalues,
                                  oparg);
            o2 = COCell_Get(o1);
            PUSH(o2);
            break;
        case OP_LOAD_CONST:
            oparg = NEXTARG();
            x = GETITEM(consts, oparg);
            CO_INCREF(x);
            PUSH(x);
            break;
        case OP_BUILD_TUPLE:
            oparg = NEXTARG();
            x = COTuple_New(oparg);
            if (x != NULL) {
                for (; --oparg >= 0;) {
                    o1 = POP();
                    COTuple_SetItem(x, oparg, o1);
                    CO_DECREF(o1);
                }
                PUSH(x);
            }
            break;
        case OP_BUILD_LIST:
            oparg = NEXTARG();
            x = COList_New(oparg);
            if (x != NULL) {
                for (; --oparg >= 0;) {
                    o1 = POP();
                    COList_SetItem(x, oparg, o1);
                    CO_DECREF(o1);
                }
                PUSH(x);
            }
            break;
        case OP_DICT_BUILD:
            oparg = NEXTARG();
            x = CODict_New();
            PUSH(x);
            break;
        case OP_DICT_ADD:
            o1 = POP();
            o2 = POP();
            o3 = POP();
            CODict_SetItem(o3, o2, o1);
            x = o3;
            CO_DECREF(o1);
            CO_DECREF(o2);
            PUSH(x);
            break;
        case OP_STORE_NAME:
            oparg = NEXTARG();
            o1 = GETITEM(names, oparg);
            o2 = POP();
            COObject_set(o1, o2);
            CO_DECREF(o2);
            break;
        case OP_STORE_UPVAL:
            oparg = NEXTARG();
            o1 = COTuple_GET_ITEM(((COFunctionObject *)func)->func_upvalues,
                                  oparg);
            o2 = POP();
            COCell_Set(o1, o2);
            CO_DECREF(o2);
            break;
        case OP_STORE_LOCAL:
            oparg = NEXTARG();
            o1 = POP();
            SETLOCAL(oparg, o1);
            break;
        case OP_JMPZ:
            oparg = NEXTARG();
            o1 = POP();
            if (o1 == CO_True) {
            } else if (o1 == CO_False) {
                JUMPTO(oparg);
            } else {
                err = COObject_IsTrue(o1);
                if (err > 0)
                    err = 0;
                else if (err == 0)
                    JUMPTO(oparg);
            }
            CO_DECREF(o1);
            break;
        case OP_JMP:
            oparg = NEXTARG();
            JUMPBY(oparg);
            break;
        case OP_JMPX:
            oparg = NEXTARG();
            JUMPTO(oparg);
            break;
        case OP_DECLARE_FUNCTION:
            o1 = POP();
            x = COFunction_New(o1);
            COCodeObject *c = (COCodeObject *)o1;
            for (int i = 0; i < CO_SIZE(c->co_upvals); i++) {
                COObject *name = COTuple_GET_ITEM(c->co_upvals, i);
                COObject *upvalue = COObject_get(name);
                if (!upvalue) {
                    // local variables 
                    for (int j = 0; j < COTuple_Size(localnames); j++) {
                        if (COObject_CompareBool
                            (COTuple_GET_ITEM(localnames, j), name, Cmp_EQ)) {
                            upvalue = GETLOCAL(j);
                        }
                    }
                }
                COObject *cell = COCell_New(upvalue);
                COTuple_SET_ITEM(((COFunctionObject *)x)->func_upvalues, i,
                                 cell);
            }
            CO_DECREF(o1);
            PUSH(x);
            break;
        case OP_CALL_FUNCTION:
            o1 = POP();
            oparg = NEXTARG();
            COObject *args = COTuple_New(oparg);
            while (--oparg >= 0) {
                o2 = POP();
                COTuple_SetItem(args, oparg, o2);
                CO_DECREF(o2);
            }

            if (COCFunction_Check(o1)) {
                COCFunction cfunc = COCFunction_GET_FUNCTION(o1);
                x = cfunc(NULL, args);
                CO_DECREF(o1);
                CO_DECREF(args);
                PUSH(x);
            } else if (COFunction_Check(o1)) {
                ssize_t i = CO_SIZE(args);
                while (--i >= 0) {
                    COList_Append(funcargs, COTuple_GET_ITEM(args, i));
                }
                CO_DECREF(args);
                TS(frame)->f_stacktop = stack_top;
                TS(frame)->f_lasti = (int)(next_code - first_code);
                TS(frame) =
                    (COFrameObject *)COFrame_New((COObject *)TS(frame), o1,
                                                 globals);
                CO_DECREF(o1);
                func = o1;
                goto new_frame;
            } else {
                x = COObject_Call(o1, args);
                CO_DECREF(args);
                CO_DECREF(o1);
                PUSH(x);
            }
            break;
        case OP_RETURN:
            o1 = POP();
            TS(frame)->f_stacktop = stack_top;
            TS(frame)->f_lasti = (int)(next_code - first_code);
            COFrameObject *old_frame = (COFrameObject *)TS(frame);
            TS(frame) = (COFrameObject *)old_frame->f_prev;
            CO_DECREF(old_frame);
            if (!TS(frame)) {
                CO_DECREF(o1);
                goto vm_exit;
            }
            // init function return
            *(TS(frame)->f_stacktop++) = o1;
            goto new_frame;
            break;
        case OP_SETUP_LOOP:
            oparg = NEXTARG();
            COFrameBlock_Setup(TS(frame), opcode, oparg, STACK_LEVEL());
            break;
        case OP_SETUP_TRY:
            oparg = NEXTARG();
            COFrameBlock_Setup(TS(frame), opcode, oparg, STACK_LEVEL());
            break;
        case OP_POP_BLOCK:
            {
                COFrameBlock *fb = COFrameBlock_Pop(TS(frame));
                UNWIND_BLOCK(fb);
            }
            break;
        case OP_POP_TRY:
            {
                COFrameBlock *fb = COFrameBlock_Pop(TS(frame));
                UNWIND_BLOCK(fb);
            }
            break;
        case OP_BREAK_LOOP:
            status = STATUS_BREAK;
            break;
        case OP_CONTINUE_LOOP:
            oparg = NEXTARG();
            status = STATUS_CONTINUE;
            break;
        case OP_THROW:
            oparg = NEXTARG();
            if (oparg == 1) {
                o1 = POP();
            } else if (oparg == 0) {
                o1 = CO_None;
            } else {
                error("error oparg");
            }
            status = STATUS_EXCEPTION;
            COErr_SetObject(COException_SystemError, o1);
            break;
        case OP_DUP_TOP:
            o1 = TOP();
            CO_INCREF(o1);
            PUSH(o1);
            break;
        case OP_POP_TOP:
            o1 = POP();
            CO_DECREF(o1);
            break;
        case OP_END_TRY:
            o1 = POP();
            COErr_SetString(COException_SystemError, COStr_AsString(o1));
            status = STATUS_EXCEPTION;
            CO_DECREF(o1);
            break;
        case OP_SETUP_FINALLY:
            oparg = NEXTARG();
            COFrameBlock_Setup(TS(frame), opcode, oparg, STACK_LEVEL());
            break;
        case OP_END_FINALLY:
            o1 = POP();
            if (o1 != CO_None) {
                COErr_SetString(COException_SystemError, COStr_AsString(o1));
                status = STATUS_EXCEPTION;
            }
            CO_DECREF(o1);
            break;
        case OP_STORE_SUBSCRIPT:
            o1 = TOP();
            o2 = SECOND();
            o3 = THIRD();
            STACK_ADJ(-3);
            if (COList_Check(o3)) {
                err = COList_SetItem(o3, COInt_AsSsize_t(o2), o1);
            } else if (CODict_Check(o3)) {
                CODict_SetItem(o3, o2, o1);
            } else {
                error("wrong store subscript");
            }
            CO_DECREF(o1);
            CO_DECREF(o2);
            CO_DECREF(o3);
            break;
        case OP_GET_ITER:
            o1 = TOP();
            x = COObject_GetIter(o1);
            CO_DECREF(o1);
            SET_TOP(x);
            break;
        case OP_FOR_ITER:
            oparg = NEXTARG();
            o1 = TOP();
            x = (*o1->co_type->tp_iternext) (o1);
            if (x) {
                PUSH(x);
                break;
            }
            o1 = POP();
            CO_DECREF(o1);
            JUMPTO(oparg);
            break;
        default:
            error("unknown handle for opcode(%ld)\n", opcode);
        }

fast_end:

        while (status != STATUS_NONE && TS(frame)->f_iblock > 0) {
            COFrameBlock *fb =
                &TS(frame)->f_blockstack[TS(frame)->f_iblock - 1];
            if (fb->fb_type == OP_SETUP_LOOP && status == STATUS_CONTINUE) {
                status = STATUS_NONE;
                JUMPTO(oparg);
                break;
            }
            TS(frame)->f_iblock--;
            UNWIND_BLOCK(fb);
            if (fb->fb_type == OP_SETUP_LOOP && status == STATUS_BREAK) {
                status = STATUS_NONE;
                JUMPTO(fb->fb_handler);
                break;
            }
            if (fb->fb_type == OP_SETUP_TRY && status == STATUS_EXCEPTION) {
                status = STATUS_NONE;
                COObject *exc, *val, *tb;
                COErr_Fetch(&exc, &val, &tb);
                PUSH(val);
                JUMPTO(fb->fb_handler);
                break;
            }
        }

        /* End the loop if we still have an error (or return) */
        x = NULL;
        if (status != STATUS_NONE)
            break;
    }

vm_exit:

    /* Clear frame stack. */
    while (TS(frame)) {
        COFrameObject *tmp_frame = (COFrameObject *)TS(frame)->f_prev;
        CO_DECREF(TS(frame));
        TS(frame) = tmp_frame;
    }

    return x;
}