static void throw_loop_edge_prepare( gravm_runstack_t *self) { if(self->cb->edge_abort != NULL && it_prev(&self->top->out_it)) /* previously prepared edges for which abort() needs to be called? */ self->top->out_cur = self->top->out_it.it.element; else self->top->out_cur = NULL; self->top->ip = GRAVM_RS_IP_BEGIN_EDGE_UNPREPARE; }
static void throw_begin_edge_unprepare( gravm_runstack_t *self) { int ret; if(self->top->out_cur != NULL) { /* prepared edges remaining, abort them */ assert(self->cb->edge_abort != NULL); ret = self->cb->edge_abort(self->user, self->throw_code, self->top->out_cur->id, self->top->user); self->invoked = true; if(it_prev(&self->top->out_it)) self->top->out_cur = self->top->out_it.it.element; else self->top->out_cur = NULL; switch(ret) { case GRAVM_RS_SUCCESS: return; THROW_EXCEPTION_CASES } }
static void exec_loop_edge_unprepare( gravm_runstack_t *self) { int ret; assert(self->cb->edge_unprepare != NULL); assert(self->top->out_cur != NULL); ret = self->cb->edge_unprepare(self->user, self->top->out_cur->id, self->top->user); self->invoked = true; switch(ret) { case GRAVM_RS_SUCCESS: if(it_prev(&self->top->out_it)) self->top->out_cur = self->top->out_it.it.element; else self->top->ip++; return; EXEC_EXCEPTION_CASES } }
static void _rt_run(struct _rt_invocation* inv) { struct _rt_stack* sp = inv->top->sp; while(1) { int tmp; switch(*inv->top->pc++) { case OP_NOOP: break; case OP_DEBUG: break; case OP_POP: sp++; break; case OP_ADD: if(_rt_num(inv,sp) || _rt_num(inv,sp + 1)) break; sp[1].num += sp[0].num; sp++; break; case OP_SUB: if(_rt_num(inv,sp) || _rt_num(inv,sp + 1)) break; sp[1].num -= sp[0].num; sp++; break; case OP_MUL: if(_rt_num(inv,sp) || _rt_num(inv,sp + 1)) break; sp[1].num *= sp[0].num; sp++; break; case OP_DIV: if(_rt_num(inv,sp) || _rt_num(inv,sp + 1) || sp->num == 0) break; sp[1].num /= sp[0].num; sp++; break; case OP_NOT: sp->num = _rt_test(sp) == 0; sp->type = STACK_NUM; break; case OP_NEG: if(_rt_num(inv,sp)) break; sp->num *= -1; break; case OP_EQ: sp[1].num = _rt_equal(inv,sp,sp + 1); sp[1].type = STACK_NUM; sp++; break; case OP_NE: sp[1].num = _rt_equal(inv,sp,sp + 1) == 0; sp[1].type = STACK_NUM; sp++; break; case OP_GE: sp[1].num = _rt_compare(inv,sp,sp + 1) >= 0; sp++; break; case OP_GT: sp[1].num = _rt_compare(inv,sp,sp + 1) > 0; sp++; break; case OP_LE: sp[1].num = _rt_compare(inv,sp,sp + 1) <= 0; sp++; break; case OP_LT: sp[1].num = _rt_compare(inv,sp,sp + 1) < 0; sp++; break; case OP_BNZ: // emit Is (branch forward conditional) tmp = *((ushort*)inv->top->pc); inv->top->pc += sizeof(ushort); if(_rt_test(sp)) inv->top->pc += tmp; sp++; case OP_BZ: // emit Is (branch forward conditional) tmp = *((ushort*)inv->top->pc); inv->top->pc += sizeof(ushort); if(_rt_test(sp) == 0) inv->top->pc += tmp; sp++; break; case OP_BR: // emit Is (branch forward) tmp = *((ushort*)inv->top->pc); inv->top->pc += tmp + sizeof(ushort); break; case OP_LOOP: // JIT-HOOK // emit Is (branch back) tmp = *((ushort*)inv->top->pc); inv->top->pc -= tmp - sizeof(ushort); break; case OP_ZLOOP: tmp = *((ushort*)inv->top->pc); inv->top->pc += sizeof(ushort); if(_rt_test(sp) == 0) inv->top->pc -= tmp; sp++; break; case OP_NZLOOP: tmp = *((ushort*)inv->top->pc); inv->top->pc += sizeof(ushort); if(_rt_test(sp)) inv->top->pc -= tmp; sp++; break; case OP_FREE: // emit Ic2 (byte,byte) tmp = *inv->top->pc++; while(tmp-- > 0) _rt_free(inv,&inv->top->vars[tmp + *inv->top->pc]); inv->top->pc++; break; case OP_NULL: // remove sp--; sp->type = STACK_NULL; break; case OP_IMM: // emit II (imm short) sp--; sp->type = STACK_NUM; sp->num = *((short*)inv->top->pc); inv->top->pc += sizeof(short); break; case OP_STR: // emit Is sp--; sp->type = STACK_RO_PTR; sp->single_ptr = inv->top->code->strings; st_move(inv->t,&sp->single_ptr,inv->top->pc,sizeof(ushort)); inv->top->pc += sizeof(ushort); break; case OP_OBJ: sp--; sp->type = STACK_OBJ; sp->ptr = sp->obj = inv->top->object; cle_skip_header(inv->hdl->inst,&sp->ptr); break; case OP_NEW: tmp = *((ushort*)inv->top->pc); inv->top->pc += sizeof(ushort); sp--; // if(cle_goto_object_cdat(inv->hdl->inst,inv->top->pc,tmp,&sp->obj)) if (1) _rt_error(inv,__LINE__); else { inv->top->pc += tmp; if(_rt_new_obj(inv,sp)) _rt_error(inv,__LINE__); } break; case OP_CLONE: if(sp->type != STACK_OBJ) _rt_error(inv,__LINE__); else if(_rt_new_obj(inv,sp)) _rt_error(inv,__LINE__); break; case OP_ID: sp--; sp->type = STACK_OBJ; sp->obj = inv->top->object; _rt_type_id(inv,sp); break; case OP_IDO: _rt_type_id(inv,sp); break; case OP_FIND: inv->top->pc++; if(sp->type == STACK_PTR || sp->type == STACK_RO_PTR) { if(cle_goto_object(inv->hdl->inst,sp->single_ptr,&sp->obj)) sp->type = STACK_NULL; else { sp->ptr = sp->obj; cle_skip_header(inv->hdl->inst,&sp->ptr); sp->type = STACK_OBJ; } } else _rt_error(inv,__LINE__); break; case OP_IT: inv->top->pc++; sp--; switch(sp[1].type) { case STACK_PROP: // try to start iterator on value break; case STACK_COLLECTION: it_create(inv->t,&sp->it,&sp[1].ptr); sp->type = STACK_ITERATOR_COL; break; case STACK_PTR: case STACK_RO_PTR: it_create(inv->t,&sp->it,&sp[1].single_ptr); sp->type = STACK_ITERATOR; break; default: _rt_error(inv,__LINE__); } break; case OP_INEXT: tmp = *inv->top->pc++; switch(sp->type) { case STACK_ITERATOR: sp->num = it_next(inv->t,0,&sp->it,0); break; case STACK_ITERATOR_COL: sp->num = it_next(inv->t,0,&sp->it,sizeof(oid)); break; default: _rt_error(inv,__LINE__); } sp->type = STACK_NUM; break; case OP_IPREV: tmp = *inv->top->pc++; switch(sp->type) { case STACK_ITERATOR: sp->num = it_prev(inv->t,0,&sp->it,0); break; case STACK_ITERATOR_COL: sp->num = it_prev(inv->t,0,&sp->it,sizeof(oid)); break; default: _rt_error(inv,__LINE__); } sp->type = STACK_NUM; break; case OP_IKEY: inv->top->pc++; if(sp->type != STACK_ITERATOR && sp->type != STACK_ITERATOR_COL) _rt_error(inv,__LINE__); else { st_ptr pt; st_empty(inv->t,&pt); st_append(inv->t,&pt,sp->it.kdata,sp->it.kused); sp->single_ptr = sp->single_ptr_w = pt; sp->type = STACK_PTR; } break; case OP_IVAL: inv->top->pc++; if(sp->type == STACK_ITERATOR) { st_ptr pt; if(it_current(inv->t,&sp->it,&pt) == 0) { sp->single_ptr = sp->single_ptr_w = pt; sp->type = STACK_PTR; } else sp->type = STACK_NULL; } else if(sp->type == STACK_ITERATOR_COL) { if(sp->it.kused == sizeof(oid)) { // TODO: move to object.c st_ptr pt = inv->hdl->inst.root; st_move(inv->t,&pt,sp->it.kdata,sizeof(oid)); sp->ptr = sp->obj = pt; cle_skip_header(inv->hdl->inst,&sp->ptr); sp->type = STACK_OBJ; } else sp->type = STACK_NULL; } else _rt_error(inv,__LINE__); break; case OP_OMV: tmp = *((ushort*)inv->top->pc); inv->top->pc += sizeof(ushort); sp--; sp->obj = inv->top->object; if(cle_get_property_host(inv->hdl->inst,&sp->ptr,inv->top->pc,tmp) < 0) { sp->type = STACK_NULL; inv->top->pc += tmp; } else { inv->top->pc += tmp; sp->ptr = sp->obj; cle_skip_header(inv->hdl->inst,&sp->ptr); _rt_get(inv,&sp); } break; case OP_MV: tmp = *((ushort*)inv->top->pc); inv->top->pc += sizeof(ushort); if(_rt_move(inv,&sp,inv->top->pc,tmp)) sp->type = STACK_NULL; inv->top->pc += tmp; break; case OP_RIDX: if(sp->type == STACK_NUM) { char buffer[sizeof(rt_number) + HEAD_SIZE]; buffer[0] = 0; buffer[1] = 'N'; memcpy(buffer + 2,&sp->num,sizeof(rt_number)); sp++; if(_rt_move(inv,&sp,buffer,sizeof(buffer))) sp->type = STACK_NULL; } else if(sp->type == STACK_PTR || sp->type == STACK_RO_PTR) { st_ptr mv = sp->single_ptr; sp++; if(_rt_move_st(inv,&sp,&mv)) sp->type = STACK_NULL; } break; case OP_LVAR: sp--; *sp = inv->top->vars[*inv->top->pc++]; break; // writer case OP_POPW: if(sp->type == STACK_OUTPUT) sp->out->pop(sp->outdata); else sp++; break; case OP_DMVW: tmp = *((ushort*)inv->top->pc); inv->top->pc += sizeof(ushort); switch(sp->type) { case STACK_REF: if(sp->var->type == STACK_NULL) { st_empty(inv->t,&sp->var->single_ptr_w); sp->var->single_ptr = sp->var->single_ptr_w; } else if(sp->var->type != STACK_PTR) { _rt_error(inv,__LINE__); return; } sp->single_ptr_w = sp->var->single_ptr; sp->single_ptr = sp->single_ptr_w; sp->type = STACK_PTR; case STACK_PTR: sp--; sp[0] = sp[1]; st_insert(inv->t,&sp->single_ptr_w,inv->top->pc,tmp); break; case STACK_OUTPUT: if(inv->response_started == 0) { sp->out->start(sp->outdata); inv->response_started = 1; } else inv->response_started = 2; sp->out->push(sp->outdata); sp->out->data(sp->outdata,inv->top->pc,tmp); } inv->top->pc += tmp; break; case OP_MVW: tmp = *((ushort*)inv->top->pc); inv->top->pc += sizeof(ushort); switch(sp->type) { case STACK_PTR: st_insert(inv->t,&sp->single_ptr_w,inv->top->pc,tmp); break; case STACK_OUTPUT: if(inv->response_started == 0) { sp->out->start(sp->outdata); inv->response_started = 1; } else inv->response_started = 2; sp->out->data(sp->outdata,inv->top->pc,tmp); } inv->top->pc += tmp; break; case OP_WIDX: // replace by OP_OUT ? _rt_out(inv,&sp,sp,sp + 1); sp++; break; case OP_OPEN: _rt_do_open(inv,&sp); break; case OP_OPEN_POP: // unfinished output if(inv->response_started == 2) sp->out->next(sp->outdata); sp->out->end(sp->outdata,0,0); inv->response_started = 1; tk_commit_task(sp->outtask); // well, what if something went wrong?? sp++; break; // receive input case OP_RECV: sp += *inv->top->pc++; inv->top->sp = sp; return; case OP_SET: if(inv->top->is_expr != 0) _rt_error(inv,__LINE__); else if(sp[1].type != STACK_PROP) _rt_error(inv,__LINE__); else { switch(sp->type) { case STACK_PROP: if(cle_identity_value(inv->hdl->inst,sp->prop_id,sp->prop_obj,&sp->ptr)) _rt_error(inv,__LINE__); if(cle_set_property_ptr(inv->hdl->inst,sp[1].prop_obj,sp[1].prop_id,&sp[1].ptr)) _rt_error(inv,__LINE__); // might not be a good idea if prop-val is a mem-ref st_copy_st(inv->t,&sp[1].ptr,&sp->ptr); break; case STACK_RO_PTR: // link if(cle_set_property_ptr(inv->hdl->inst,sp[1].prop_obj,sp[1].prop_id,&sp[1].ptr)) _rt_error(inv,__LINE__); st_link(inv->t,&sp[1].ptr,&sp->single_ptr); break; case STACK_PTR: // copy if(cle_set_property_ptr(inv->hdl->inst,sp[1].prop_obj,sp[1].prop_id,&sp[1].ptr)) _rt_error(inv,__LINE__); st_copy_st(inv->t,&sp[1].ptr,&sp->single_ptr); break; case STACK_NUM: // bin-num if(cle_set_property_num(inv->hdl->inst,sp[1].prop_obj,sp[1].prop_id,sp->num)) _rt_error(inv,__LINE__); break; case STACK_OBJ: // obj-ref if(cle_set_property_ref(inv->hdl->inst,sp[1].prop_obj,sp[1].prop_id,sp->obj)) _rt_error(inv,__LINE__); break; case STACK_CODE: // write out path/event to method/handler if(st_move(inv->t,&sp->single_ptr,"p",1) == 0) { if(cle_set_property_ptr(inv->hdl->inst,sp[1].prop_obj,sp[1].prop_id,&sp[1].ptr)) _rt_error(inv,__LINE__); st_copy_st(inv->t,&sp[1].ptr,&sp->single_ptr); break; } // or null default: // empty / null if(cle_set_property_ptr(inv->hdl->inst,sp[1].prop_obj,sp[1].prop_id,&sp[1].ptr)) _rt_error(inv,__LINE__); } } sp += 2; break; case OP_MERGE: switch(sp->type) { case STACK_PROP: if(inv->top->is_expr != 0) _rt_error(inv,__LINE__); else if(cle_set_property_ptr(inv->hdl->inst,sp->prop_obj,sp->prop_id,&sp->single_ptr)) _rt_error(inv,__LINE__); else { sp->single_ptr_w = sp->single_ptr; sp->type = STACK_PTR; } break; case STACK_REF: if(sp->var->type == STACK_NULL) { st_empty(inv->t,&sp->var->single_ptr); sp->var->single_ptr_w = sp->var->single_ptr; sp->var->type = STACK_PTR; } else if(sp->var->type != STACK_PTR) _rt_error(inv,__LINE__); case STACK_PTR: case STACK_OUTPUT: break; default: _rt_error(inv,__LINE__); } break; case OP_2STR: tmp = *inv->top->pc++; // vars if(tmp != 1) { _rt_error(inv,__LINE__); break; } // fall throu case OP_CAT: { struct _rt_stack to; st_empty(inv->t,&to.single_ptr); to.single_ptr_w = to.single_ptr; to.type = STACK_PTR; _rt_out(inv,&sp,&to,sp); *sp = to; } break; case OP_NEXT: // non-string (concat) out-ing [OUT Last Tree] if(sp[1].type == STACK_REF) { if(sp[1].var->type == STACK_NULL) *sp[1].var = *sp; else _rt_ref_out(inv,&sp,sp + 1); } else { if(_rt_out(inv,&sp,sp + 1,sp) == 0) { sp++; if(inv->response_started == 2 && sp->type == STACK_OUTPUT) { inv->response_started = 1; sp->out->next(sp->outdata); } } } break; case OP_OUTL: // TODO: stream out structures case OP_OUT: // stream out string if(sp[1].type == STACK_REF) _rt_ref_out(inv,&sp,sp + 1); else _rt_out(inv,&sp,sp + 1,sp); sp++; break; case OP_AVAR: inv->top->vars[*inv->top->pc++] = *sp; sp++; break; case OP_DEFP: // emit Is2 (branch forward) tmp = *inv->top->pc++; // var if(inv->top->vars[tmp].type == STACK_NULL) { sp--; inv->top->vars[tmp].var = sp; inv->top->vars[tmp].type = STACK_REF; inv->top->pc += sizeof(ushort); } else { tmp = *((ushort*)inv->top->pc); inv->top->pc += tmp + sizeof(ushort); } break; case OP_END: tmp = inv->top->code->body.maxparams; while(tmp-- > 0) _rt_free(inv,&inv->top->vars[tmp]); if(inv->top->parent == 0) { // unfinished output? -> next if(inv->response_started == 2) inv->hdl->response->next(inv->hdl->respdata); cle_stream_end(inv->hdl); return; } else { struct _rt_callframe* cf = inv->top; inv->top = inv->top->parent; sp = inv->top->sp; // unref page of origin tk_unref(inv->t,cf->pg); } break; case OP_DOCALL: tmp = *inv->top->pc++; // params if(_rt_call(inv,sp,tmp) == 0) { inv->top->parent->sp = sp + 1 + tmp; // return-stack *(--inv->top->sp) = *(sp + 1 + tmp); // copy output-target sp = inv->top->sp; // set new stack } break; case OP_DOCALL_N: tmp = *inv->top->pc++; // params if(_rt_call(inv,sp,tmp) == 0) { inv->top->parent->sp = sp + tmp; // return-stack inv->top->sp--; inv->top->sp->type = STACK_REF; // ref to sp-top inv->top->sp->var = sp + tmp; inv->top->sp->var->type = STACK_NULL; sp = inv->top->sp; // set new stack } break; case OP_ERROR: // system exception return; default: _rt_error(inv,__LINE__); } } }