Ejemplo n.º 1
0
FAKE_API void fkresumeps(fake * fk, bool & isend)
{
	FKLOG("fkresumeps %p", fk);

	isend = false;

	// 上次的processor
	pool<processor>::node * n = 0;
	GET_CUR_PROCESSOR(n, fk->rn);
	if (UNLIKE(!n))
	{
		variant * ret = 0;
		bool err = false;
		PS_PUSH_AND_GET(fk->ps, ret);
		*ret = NILV;
		FKLOG("fkresumeps %p no processor", fk);
		CHECK_ERR(err);
		return;
	}

	// 先pop防止重入
	POP_CUR_PROCESSOR(fk->rn);
	
	processor & pro = n->t;
	pro.run();
	if (LIKE(!PROCESS_END(pro)))
	{
		// 重新塞入
		PUSH_CUR_PROCESSOR(n, fk->rn);
	
		variant * ret = 0;
		bool err = false;
		PS_PUSH_AND_GET(fk->ps, ret);
		*ret = NILV;
		FKLOG("fkresumeps %p not end", fk);
		CHECK_ERR(err);
		return;
	}

	// 结束了
	variant * ret = 0;
	bool err = false;
	PS_PUSH_AND_GET(fk->ps, ret);
	*ret = ROUTINE_GETRET(*pro.m_entryroutine);
	CHECK_ERR(err);

	POOL_PUSH(fk->pp, n);
	
	fk->rn.rundeps--;
	
	isend = true;
	
	FKLOG("fkresumeps %p OK", fk);
}
Ejemplo n.º 2
0
// 调用函数
FAKE_API void fkrunps(fake * fk, const char * func)
{
	FKLOG("fkrunps %p %s", fk, func);

	fk->rn.rundeps++;

	// 清空运行环境	
	fk->clearerr();

	// 分配个
	pool<processor>::node * n = 0;
	if (UNLIKE(POOL_EMPTY(fk->pp)))
	{
		POOL_GROW(fk->pp, pool<processor>::node, n);
		PROCESS_INI(n->t, fk);
	}
	POOL_POP(fk->pp, n);
	assert(ARRAY_EMPTY(n->t.m_pl.l));
	assert(n->t.m_routine_num == 0);
	processor & pro = n->t;
	PROCESS_CLEAR(pro);
	variant funcv;
	V_SET_STRING(&funcv, func);
	routine * r = pro.start_routine(funcv, 0, 0);

	PUSH_CUR_PROCESSOR(n, fk->rn);
	// 单独执行,下次再跑run
	if (UNLIKE(fk->rn.stepmod))
	{
		variant * ret = 0;
		bool err = false;
		PS_PUSH_AND_GET(fk->ps, ret);
		*ret = NILV;
		FKLOG("fkrunps %p %s yield", fk, func);
		CHECK_ERR(err);
		return;
	}
	
	pro.run();
	POP_CUR_PROCESSOR(fk->rn);
	
	variant * ret = 0;
	bool err = false;
	PS_PUSH_AND_GET(fk->ps, ret);
	*ret = ROUTINE_GETRET(*r);
	CHECK_ERR(err);

	POOL_PUSH(fk->pp, n);
	
	fk->rn.rundeps--;
	
	FKLOG("fkrunps %p %s OK", fk, func);
}
Ejemplo n.º 3
0
FAKE_API void fkpspushuint64(fake * fk, uint64_t ret)
{
	bool err = false;
	variant * v = 0;
	PS_PUSH_AND_GET(fk->ps, v);
	V_SET_UUID(v, ret);
	CHECK_ERR(err);
}
Ejemplo n.º 4
0
FAKE_API void fkpspushbool(fake * fk, bool ret)
{
	bool err = false;
	variant * v = 0;
	PS_PUSH_AND_GET(fk->ps, v);
	V_SET_REAL(v, ret);
	CHECK_ERR(err);
}
Ejemplo n.º 5
0
FAKE_API void fkpspushccharptr(fake * fk, const char * ret)
{
	bool err = false;
	variant * v = 0;
	PS_PUSH_AND_GET(fk->ps, v);
	V_SET_STRING(v, ret);
	CHECK_ERR(err);
}
Ejemplo n.º 6
0
// map
void buildin_map(fake * fk, interpreter * inter)
{
	bool err = false;
	variant_map * m = fk->con.newmap();
	variant * v = 0;
	PS_PUSH_AND_GET(fk->ps, v);
	V_SET_MAP(v, m);
}
Ejemplo n.º 7
0
// array
void buildin_array(fake * fk, interpreter * inter)
{
	bool err = false;
	variant_array * a = fk->con.newarray();
	variant * v = 0;
	PS_PUSH_AND_GET(fk->ps, v);
	V_SET_ARRAY(v, a);
}
Ejemplo n.º 8
0
FAKE_API void fkpspushpointer(fake * fk, void * p, const char * type)
{
	bool err = false;
	variant * v = 0;
	PS_PUSH_AND_GET(fk->ps, v);
	if (UNLIKE(p == 0))
	{
		V_SET_NIL(v);
	}
	else
	{
		V_SET_POINTER(v, p, type);
	}
	CHECK_ERR(err);
}
Ejemplo n.º 9
0
// getconst
void buildin_getconst(fake * fk, interpreter * inter)
{	
	bool err = false;
	const char * str = fkpspopcstrptr(fk);
	
	variant * v = 0;
	PS_PUSH_AND_GET(fk->ps, v);
	
	variant * gcv = fk->pa.get_const_define(str);
	if (gcv)
	{
		*v = *gcv;
	}
	else
	{
		*v = NILV;
	}	
}
Ejemplo n.º 10
0
int interpreter::run(int cmdnum)
{
	fake * fk = m_fk;
	bool & err = m_isend;
	int i = 0;
	
	// 栈溢出检查
	if (UNLIKE((int)ARRAY_MAX_SIZE(m_stack) > m_fk->cfg.stack_max))
	{	
		m_isend = true;
		seterror(fk, efk_run_inter_error, fkgetcurfile(fk), fkgetcurline(fk), fkgetcurfunc(fk), "stack too big %d", ARRAY_MAX_SIZE(m_stack));
		return 0;
	}

	// 切换检查
	if (UNLIKE(m_sleeping))
	{
		if (LIKE(m_yieldtime))
		{
			m_yieldtime--;
			return 0;
		}
		else if (LIKE(fkgetmstick() < m_wakeuptime))
		{
			return 0;
		}
		else
		{
			m_wakeuptime = 0;
		}
	}
	
	if (UNLIKE(m_isend))
	{
		return 0;
	}
	
	while (1)
	{
		// 当前函数走完
		if (UNLIKE(m_ip >= (int)FUNC_BINARY_CMDSIZE(*m_fb)))
		{
			FKLOG("pop stack %s", FUNC_BINARY_NAME(*m_fb));
			
			// 记录profile
			if (UNLIKE(m_fk->pf.isopen()))
			{
				uint32_t calltime = 0;
				BP_GET_CALLTIME(m_bp, calltime);
				m_fk->pf.add_func_sample(FUNC_BINARY_NAME(*m_fb), fkgetmstick() - calltime);
			}
			
			// 标记
			FUNC_BINARY_USE(*m_fb)--;
			
			// 更新
			if (UNLIKE(!FUNC_BINARY_USE(*m_fb) && FUNC_BINARY_BACKUP(*m_fb)))
			{
				FUNC_BINARY_BACKUP_MOVE(*m_fb);
			}
			
			// 出栈
			int oldretnum = 0;
			BP_GET_RETNUM(m_bp, oldretnum);
			int callbp = 0;
			BP_GET_BP(m_bp, callbp);
			BP_GET_FB(m_bp, m_fb);
			BP_GET_IP(m_bp, m_ip);
			int oldbp = m_bp;
			m_sp = m_bp - BP_SIZE - oldretnum;
			m_bp = callbp;
			
			// 所有都完
			if (UNLIKE(BP_END(m_bp)))
			{
				FKLOG("stack empty end");
				m_isend = true;
				break;
			}
			// 塞返回值
			else
			{
				for (int i = 0; i < oldretnum; i++)
				{
					int oldretpos = 0;
					BP_GET_RETPOS(oldbp, oldretnum, oldretpos, i);
					
					variant * ret;
					GET_VARIANT(*m_fb, m_bp, ret, oldretpos);
					*ret = m_ret[i];
				}
			}
			continue;
		}

		int code = COMMAND_CODE(GET_CMD(*m_fb, m_ip));

		FKLOG("next %d %d %s", COMMAND_TYPE(GET_CMD(*m_fb, m_ip)), code, OpCodeStr(code));
			
		assert (COMMAND_TYPE(GET_CMD(*m_fb, m_ip)) == COMMAND_OPCODE);

		m_ip++;

		if (UNLIKE(m_fk->pf.isopen()))
		{
			m_fk->pf.add_code_sample(code);
		}

		// 执行对应命令,放一起switch效率更高,cpu有缓存
		switch (code)
		{
		case OPCODE_ASSIGN:
			{
				// 赋值dest,必须为栈上或容器内
				if (UNLIKE(!(CHECK_STACK_POS(*m_fb, m_ip) || CHECK_CONTAINER_POS(*m_fb, m_ip))))
				{	
					err = true;
					seterror(fk, efk_run_inter_error, fkgetcurfile(fk), fkgetcurline(fk), fkgetcurfunc(fk), "interpreter assign error, dest is not stack or container, type %s", POS_TYPE_NAME(*m_fb, m_ip));
					break;
				}

				variant * varv = 0;
				LOG_VARIANT(*m_fb, m_ip, "var");
				GET_VARIANT(*m_fb, m_bp, varv, m_ip);
				m_ip++;
				
				// 赋值来源
				const variant * valuev = 0;
				LOG_VARIANT(*m_fb, m_ip, "value");
				GET_VARIANT(*m_fb, m_bp, valuev, m_ip);
				m_ip++;

				// 赋值
				*varv = *valuev;

				FKLOG("assign %s to %s", (vartostring(valuev)).c_str(), (vartostring(varv)).c_str());
			}
			break;
		case OPCODE_PLUS:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, PLUS);
			}
			break;
		case OPCODE_MINUS:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, MINUS);
			}
			break;
		case OPCODE_MULTIPLY:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, MULTIPLY);
			}
			break;
		case OPCODE_DIVIDE:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, DIVIDE);
			}
			break;
		case OPCODE_DIVIDE_MOD:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, DIVIDE_MOD);
			}
			break;
		case OPCODE_AND:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, AND);
			}
			break;
		case OPCODE_OR:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, OR);
			}
			break;
		case OPCODE_LESS:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, LESS);
			}
			break;
		case OPCODE_MORE:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, MORE);
			}
			break;
		case OPCODE_EQUAL:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, EQUAL);
			}
			break;
		case OPCODE_MOREEQUAL:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, MOREEQUAL);
			}
			break;
		case OPCODE_LESSEQUAL:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, LESSEQUAL);
			}
			break;
		case OPCODE_NOTEQUAL:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, NOTEQUAL);
			}
			break;
		case OPCODE_NOT:
			{
				MATH_SINGLE_OPER(*m_fb, m_bp, m_ip, NOT);
			}
			break;
		case OPCODE_AND_JNE:
			{
				MATH_OPER_JNE(*m_fb, m_bp, m_ip, AND_JNE);
			}
			break;
		case OPCODE_OR_JNE:
			{
				MATH_OPER_JNE(*m_fb, m_bp, m_ip, OR_JNE);
			}
			break;
		case OPCODE_LESS_JNE:
			{
				MATH_OPER_JNE(*m_fb, m_bp, m_ip, LESS_JNE);
			}
			break;
		case OPCODE_MORE_JNE:
			{
				MATH_OPER_JNE(*m_fb, m_bp, m_ip, MORE_JNE);
			}
			break;
		case OPCODE_EQUAL_JNE:
			{
				MATH_OPER_JNE(*m_fb, m_bp, m_ip, EQUAL_JNE);
			}
			break;
		case OPCODE_MOREEQUAL_JNE:
			{
				MATH_OPER_JNE(*m_fb, m_bp, m_ip, MOREEQUAL_JNE);
			}
			break;
		case OPCODE_LESSEQUAL_JNE:
			{
				MATH_OPER_JNE(*m_fb, m_bp, m_ip, LESSEQUAL_JNE);
			}
			break;
		case OPCODE_NOTEQUAL_JNE:
			{
				MATH_OPER_JNE(*m_fb, m_bp, m_ip, NOTEQUAL_JNE);
			}
			break;
		case OPCODE_NOT_JNE:
			{
				MATH_SINGLE_OPER_JNE(*m_fb, m_bp, m_ip, NOT_JNE);
			}
			break;
		case OPCODE_JNE:
			{
				const variant * cmp = 0;
				LOG_VARIANT(*m_fb, m_ip, "cmp");
				GET_VARIANT(*m_fb, m_bp, cmp, m_ip);
				m_ip++;

				int ip = COMMAND_CODE(GET_CMD(*m_fb, m_ip));
				m_ip++;
				
				if (!(V_ISBOOL(cmp)))
				{
					FKLOG("jne %d", ip);
					m_ip = ip;
				}
				else
				{
					FKLOG("not jne %d", ip);
				}
			}
			break;
		case OPCODE_JMP:
			{
				int ip = COMMAND_CODE(GET_CMD(*m_fb, m_ip));
				m_ip++;
				
				FKLOG("jmp %d", ip);

				m_ip = ip;
			}
			break;
		case OPCODE_PLUS_ASSIGN:
			{
				MATH_ASSIGN_OPER(*m_fb, m_bp, m_ip, PLUS);
			}
			break;
		case OPCODE_MINUS_ASSIGN:
			{
				MATH_ASSIGN_OPER(*m_fb, m_bp, m_ip, MINUS);
			}
			break;
		case OPCODE_MULTIPLY_ASSIGN:
			{
				MATH_ASSIGN_OPER(*m_fb, m_bp, m_ip, MULTIPLY);
			}
			break;
		case OPCODE_DIVIDE_ASSIGN:
			{
				MATH_ASSIGN_OPER(*m_fb, m_bp, m_ip, DIVIDE);
			}
			break;
		case OPCODE_DIVIDE_MOD_ASSIGN:
			{
				MATH_ASSIGN_OPER(*m_fb, m_bp, m_ip, DIVIDE_MOD);
			}
			break;
		case OPCODE_CALL:
			{
				int calltype = COMMAND_CODE(GET_CMD(*m_fb, m_ip));
				m_ip++;

				const variant * callpos = 0;
				LOG_VARIANT(*m_fb, m_ip, "callpos");
				GET_VARIANT(*m_fb, m_bp, callpos, m_ip);
				m_ip++;

				int retnum = COMMAND_CODE(GET_CMD(*m_fb, m_ip));
				m_ip++;
				
				int retpos[MAX_FAKE_RETURN_NUM];

				for (int i = 0; i < retnum; i++)
				{
					assert(CHECK_STACK_POS(*m_fb, m_ip));
					retpos[i] = m_ip;
					m_ip++;
				}
				
				int argnum = COMMAND_CODE(GET_CMD(*m_fb, m_ip));
				m_ip++;

				paramstack & ps = *getps(m_fk);
				PS_CLEAR(ps);
				for (int i = 0; i < argnum; i++)
				{
					variant * arg = 0;
					LOG_VARIANT(*m_fb, m_ip, "arg");
					GET_VARIANT(*m_fb, m_bp, arg, m_ip);
					m_ip++;

					variant * argdest = 0;
					PS_PUSH_AND_GET(ps, argdest);
					*argdest = *arg;
				}
				
				if (LIKE(calltype == CALL_NORMAL))
				{
					call(*callpos, retnum, retpos);
				}
				else
				{
					m_processor->start_routine(*callpos, retnum, retpos);
				}
			}
			break;
		case OPCODE_RETURN:
			{
				int returnnum = COMMAND_CODE(GET_CMD(*m_fb, m_ip));
				if (UNLIKE(!returnnum))
				{
					FKLOG("return empty");
					m_ip = (*m_fb).m_size;
					break;
				}
				m_ip++;

				// 塞给ret
				for (int i = 0; i < returnnum; i++)
				{
					const variant * ret = 0;
					LOG_VARIANT(*m_fb, m_ip, "ret");
					GET_VARIANT(*m_fb, m_bp, ret, m_ip);
					m_ip++;

					m_ret[i] = *ret;

					FKLOG("return %s", (vartostring(&m_ret[i])).c_str());
				}
				
				m_ip = (*m_fb).m_size;
			}
			break;
		case OPCODE_FORBEGIN:
			{
				// 赋值dest,必须为栈上或容器内
				if (UNLIKE(!(CHECK_STACK_POS(*m_fb, m_ip) || CHECK_CONTAINER_POS(*m_fb, m_ip))))
				{	
					err = true;
					seterror(fk, efk_run_inter_error, fkgetcurfile(fk), fkgetcurline(fk), fkgetcurfunc(fk), "interpreter assign error, dest is not stack or container, type %s", POS_TYPE_NAME(*m_fb, m_ip));
					break;
				}

				// var
				variant * varv = 0;
				LOG_VARIANT(*m_fb, m_ip, "var");
				GET_VARIANT(*m_fb, m_bp, varv, m_ip);
				m_ip++;
				
				// begin
				const variant * beginv = 0;
				LOG_VARIANT(*m_fb, m_ip, "begin");
				GET_VARIANT(*m_fb, m_bp, beginv, m_ip);
				m_ip++;

				// end
				const variant * endv = 0;
				LOG_VARIANT(*m_fb, m_ip, "endv");
				GET_VARIANT(*m_fb, m_bp, endv, m_ip);
				m_ip++;

				// add
				const variant * addv = 0;
				LOG_VARIANT(*m_fb, m_ip, "addv");
				GET_VARIANT(*m_fb, m_bp, addv, m_ip);
				m_ip++;

				int jneip = COMMAND_CODE(GET_CMD(*m_fb, m_ip));
				m_ip++;

				// 赋值
				*varv = *beginv;

				// 增长
				if (LIKE(addv->data.real > 0))
				{
					// 判断是否超出
					if (UNLIKE(varv->data.real >= endv->data.real))
					{
						m_ip = jneip;
					}
				}
				else
				{
					// 判断是否小
					if (UNLIKE(varv->data.real <= endv->data.real))
					{
						m_ip = jneip;
					}
				}
			}
			break;
		case OPCODE_FORLOOP:
			{
				// var
				variant * varv = 0;
				LOG_VARIANT(*m_fb, m_ip, "var");
				GET_VARIANT(*m_fb, m_bp, varv, m_ip);
				m_ip++;
				
				// end
				const variant * endv = 0;
				LOG_VARIANT(*m_fb, m_ip, "endv");
				GET_VARIANT(*m_fb, m_bp, endv, m_ip);
				m_ip++;

				// add
				const variant * addv = 0;
				LOG_VARIANT(*m_fb, m_ip, "addv");
				GET_VARIANT(*m_fb, m_bp, addv, m_ip);
				m_ip++;

				int continueip = COMMAND_CODE(GET_CMD(*m_fb, m_ip));
				m_ip++;

				// 赋值
				V_PLUS(varv, varv, addv);

				// 增长
				if (LIKE(addv->data.real > 0))
				{
					// 判断是否超出
					if (UNLIKE(varv->data.real < endv->data.real))
					{
						m_ip = continueip;
					}
				}
				else
				{
					// 判断是否小
					if (UNLIKE(varv->data.real > endv->data.real))
					{
						m_ip = continueip;
					}
				}
			}
			break;
		case OPCODE_SLEEP:
			{
				const variant * time = 0;
				LOG_VARIANT(*m_fb, m_ip, "time");
				GET_VARIANT(*m_fb, m_bp, time, m_ip);
				m_ip++;

				uint32_t sleeptime = 0;
				V_GET_REAL(time, sleeptime);

				m_wakeuptime = fkgetmstick() + sleeptime;
				m_sleeping = true;
				return i + 1;
			}
			break;
		case OPCODE_YIELD:
			{
				const variant * time = 0;
				LOG_VARIANT(*m_fb, m_ip, "time");
				GET_VARIANT(*m_fb, m_bp, time, m_ip);
				m_ip++;

				V_GET_REAL(time, m_yieldtime);
				m_sleeping = true;
				return i + 1;
			}
			break;
		default:
			assert(0);
			FKERR("next err code %d %s", code, OpCodeStr(code));
			break;
		}
		
		if (UNLIKE(err))
		{
			// 发生错误
			m_isend = true;
		}

		if (UNLIKE(m_isend))
		{
			break;
		}
		
		i++;
		
		if (UNLIKE(i >= cmdnum))
		{
			break;
		}
	}
	
	return i;
}
Ejemplo n.º 11
0
// range
void buildin_range(fake * fk, interpreter * inter)
{
	BIF_CHECK_ARG_NUM(2);

	// pos
	int pos = fkpspop<int>(fk);

	// container
	bool err = false;
	variant * v = 0;
	PS_POP_AND_GET(fk->ps, v);

	if (v->type == variant::STRING)
	{
		if (pos >= 0 && pos < (int)v->data.str->sz)
		{
			char data[2];
			data[0] = v->data.str->s[pos];
			data[1] = 0;
			fkpspush<const char *>(fk, data);
		}
		else
		{
			fkpspush<const char *>(fk, "");
		}
	}
	else if (v->type == variant::ARRAY)
	{
		if (pos >= 0 && pos < (int)ARRAY_SIZE(v->data.va->va) && ARRAY_GET(v->data.va->va, pos))
		{
			variant * ret = 0;
			PS_PUSH_AND_GET(fk->ps, ret);
			if (ARRAY_GET(v->data.va->va, pos))
			{
				*ret = *(ARRAY_GET(v->data.va->va, pos));
			}
			else
			{
				*ret = NILV;
			}
		}
		else
		{
			fkpspush<bool>(fk, false);
		}
	}
	else if (v->type == variant::MAP)
	{
		if (pos >= 0 && pos < (int)v->data.vm->vm.size())
		{
			variant * key = 0;
			PS_PUSH_AND_GET(fk->ps, key);
			
			variant * value = 0;
			PS_PUSH_AND_GET(fk->ps, value);
			
			const fkhashmap<variant, variant *>::ele * e = v->data.vm->vm.at(pos);
			*key = e->k;
			*value = *(*e->t);
		}
		else
		{
			fkpspush<bool>(fk, false);
			fkpspush<bool>(fk, false);
		}
	}
	else
	{
		fkpspush<bool>(fk, false);
	}
}
Ejemplo n.º 12
0
int interpreter::run(int cmdnum)
{
	fake * fk = m_fk;
	bool & err = m_isend;
	int i = 0;
	
	// 栈溢出检查
	if (UNLIKE((int)ARRAY_MAX_SIZE(m_stack) > m_fk->cfg.stack_max))
	{	
		m_isend = true;
		seterror(fk, efk_run_inter_error, fkgetcurfile(fk), fkgetcurline(fk), fkgetcurfunc(fk), "stack too big %d", ARRAY_MAX_SIZE(m_stack));
		return 0;
	}

	// 切换检查
	if (UNLIKE(m_sleeping))
	{
		if (LIKE(m_yieldtime))
		{
			m_yieldtime--;
			return 0;
		}
		else if (LIKE(fkgetmstick() < m_wakeuptime))
		{
			return 0;
		}
		else
		{
			m_wakeuptime = 0;
		}
	}
	
	if (UNLIKE(m_isend))
	{
		return 0;
	}
	
	while (1)
	{
		// 当前函数走完
		if (UNLIKE(m_ip >= (int)FUNC_BINARY_CMDSIZE(*m_fb)))
		{
			FKLOG("pop stack %s", FUNC_BINARY_NAME(*m_fb));
			
			// 记录profile
			if (UNLIKE(m_fk->pf.isopen()))
			{
				uint32_t calltime = 0;
				BP_GET_CALLTIME(m_bp, calltime);
				m_fk->pf.add_func_sample(FUNC_BINARY_NAME(*m_fb), fkgetmstick() - calltime);
			}
			
			// 标记
			FUNC_BINARY_USE(*m_fb)--;
			
			// 更新
			if (UNLIKE(!FUNC_BINARY_USE(*m_fb) && FUNC_BINARY_BACKUP(*m_fb)))
			{
				FUNC_BINARY_BACKUP_MOVE(*m_fb);
			}
			
			// 出栈
			int oldretnum = 0;
			BP_GET_RETNUM(m_bp, oldretnum);
			int callbp = 0;
			BP_GET_BP(m_bp, callbp);
			BP_GET_FB(m_bp, m_fb);
			BP_GET_IP(m_bp, m_ip);
			int oldbp = m_bp;
			m_sp = m_bp - BP_SIZE - oldretnum;
			m_bp = callbp;
			
			// 所有都完
			if (UNLIKE(BP_END(m_bp)))
			{
				FKLOG("stack empty end");
				m_isend = true;
				break;
			}
			// 塞返回值
			else
			{
				for (int i = 0; i < oldretnum; i++)
				{
					int oldretpos = 0;
					BP_GET_RETPOS(oldbp, oldretnum, oldretpos, i);
					
					variant * ret;
					GET_VARIANT(*m_fb, m_bp, ret, oldretpos);
					*ret = m_ret[i];
				}
			}
			continue;
		}

		int code = COMMAND_CODE(GET_CMD(*m_fb, m_ip));

		FKLOG("next %d %d %s", COMMAND_TYPE(GET_CMD(*m_fb, m_ip)), code, OpCodeStr(code));
			
		assert (COMMAND_TYPE(GET_CMD(*m_fb, m_ip)) == COMMAND_OPCODE);

		m_ip++;

		if (UNLIKE(m_fk->pf.isopen()))
		{
			m_fk->pf.add_code_sample(code);
		}

		// 执行对应命令,放一起switch效率更高,cpu有缓存
		switch (code)
		{
		case OPCODE_ASSIGN:
			{
				// 赋值dest,必须为栈上或容器内
				if (UNLIKE(!(CHECK_STACK_POS(*m_fb, m_ip) || CHECK_CONTAINER_POS(*m_fb, m_ip))))
				{	
					err = true;
					seterror(fk, efk_run_inter_error, fkgetcurfile(fk), fkgetcurline(fk), fkgetcurfunc(fk), "interpreter assign error, dest is not stack or container, type %s", POS_TYPE_NAME(*m_fb, m_ip));
					break;
				}

				variant * varv = 0;
				LOG_VARIANT(*m_fb, m_ip, "var");
				GET_VARIANT(*m_fb, m_bp, varv, m_ip);
				if (UNLIKE(CHECK_CONST_MAP_POS(varv) || CHECK_CONST_ARRAY_POS(varv)))
				{
					err = true;
					seterror(fk, efk_run_inter_error, fkgetcurfile(fk), fkgetcurline(fk), fkgetcurfunc(fk), "interpreter assign error, dest is const container");
					break;
				}
				m_ip++;
				
				// 赋值来源
				const variant * valuev = 0;
				LOG_VARIANT(*m_fb, m_ip, "value");
				GET_VARIANT(*m_fb, m_bp, valuev, m_ip);
				m_ip++;

				// 赋值
				*varv = *valuev;

				FKLOG("assign %s to %s", (vartostring(valuev)).c_str(), (vartostring(varv)).c_str());
			}
			break;
		case OPCODE_PLUS:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, PLUS);
			}
			break;
		case OPCODE_MINUS:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, MINUS);
			}
			break;
		case OPCODE_MULTIPLY:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, MULTIPLY);
			}
			break;
		case OPCODE_DIVIDE:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, DIVIDE);
			}
			break;
		case OPCODE_DIVIDE_MOD:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, DIVIDE_MOD);
			}
			break;
		case OPCODE_STRING_CAT:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, STRING_CAT);
			}
			break;
		case OPCODE_AND:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, AND);
			}
			break;
		case OPCODE_OR:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, OR);
			}
			break;
		case OPCODE_LESS:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, LESS);
			}
			break;
		case OPCODE_MORE:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, MORE);
			}
			break;
		case OPCODE_EQUAL:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, EQUAL);
			}
			break;
		case OPCODE_MOREEQUAL:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, MOREEQUAL);
			}
			break;
		case OPCODE_LESSEQUAL:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, LESSEQUAL);
			}
			break;
		case OPCODE_NOTEQUAL:
			{
				MATH_OPER(*m_fb, m_bp, m_ip, NOTEQUAL);
			}
			break;
		case OPCODE_NOT:
			{
				MATH_SINGLE_OPER(*m_fb, m_bp, m_ip, NOT);
			}
			break;
		case OPCODE_AND_JNE:
			{
				MATH_OPER_JNE(*m_fb, m_bp, m_ip, AND_JNE);
			}
			break;
		case OPCODE_OR_JNE:
			{
				MATH_OPER_JNE(*m_fb, m_bp, m_ip, OR_JNE);
			}
			break;
		case OPCODE_LESS_JNE:
			{
				MATH_OPER_JNE(*m_fb, m_bp, m_ip, LESS_JNE);
			}
			break;
		case OPCODE_MORE_JNE:
			{
				MATH_OPER_JNE(*m_fb, m_bp, m_ip, MORE_JNE);
			}
			break;
		case OPCODE_EQUAL_JNE:
			{
				MATH_OPER_JNE(*m_fb, m_bp, m_ip, EQUAL_JNE);
			}
			break;
		case OPCODE_MOREEQUAL_JNE:
			{
				MATH_OPER_JNE(*m_fb, m_bp, m_ip, MOREEQUAL_JNE);
			}
			break;
		case OPCODE_LESSEQUAL_JNE:
			{
				MATH_OPER_JNE(*m_fb, m_bp, m_ip, LESSEQUAL_JNE);
			}
			break;
		case OPCODE_NOTEQUAL_JNE:
			{
				MATH_OPER_JNE(*m_fb, m_bp, m_ip, NOTEQUAL_JNE);
			}
			break;
		case OPCODE_NOT_JNE:
			{
				MATH_SINGLE_OPER_JNE(*m_fb, m_bp, m_ip, NOT_JNE);
			}
			break;
		case OPCODE_JNE:
			{
				const variant * cmp = 0;
				LOG_VARIANT(*m_fb, m_ip, "cmp");
				GET_VARIANT(*m_fb, m_bp, cmp, m_ip);
				m_ip++;

				int ip = COMMAND_CODE(GET_CMD(*m_fb, m_ip));
				m_ip++;
				
				if (!(V_ISBOOL(cmp)))
				{
					FKLOG("jne %d", ip);
					m_ip = ip;
				}
				else
				{
					FKLOG("not jne %d", ip);
				}
			}
			break;
		case OPCODE_JMP:
			{
				int ip = COMMAND_CODE(GET_CMD(*m_fb, m_ip));
				m_ip++;
				
				FKLOG("jmp %d", ip);

				m_ip = ip;
			}
			break;
		case OPCODE_PLUS_ASSIGN:
			{
				MATH_ASSIGN_OPER(*m_fb, m_bp, m_ip, PLUS);
			}
			break;
		case OPCODE_MINUS_ASSIGN:
			{
				MATH_ASSIGN_OPER(*m_fb, m_bp, m_ip, MINUS);
			}
			break;
		case OPCODE_MULTIPLY_ASSIGN:
			{
				MATH_ASSIGN_OPER(*m_fb, m_bp, m_ip, MULTIPLY);
			}
			break;
		case OPCODE_DIVIDE_ASSIGN:
			{
				MATH_ASSIGN_OPER(*m_fb, m_bp, m_ip, DIVIDE);
			}
			break;
		case OPCODE_DIVIDE_MOD_ASSIGN:
			{
				MATH_ASSIGN_OPER(*m_fb, m_bp, m_ip, DIVIDE_MOD);
			}
			break;
		case OPCODE_CALL:
			{
				int calltype = COMMAND_CODE(GET_CMD(*m_fb, m_ip));
				m_ip++;

				const variant * callpos = 0;
				LOG_VARIANT(*m_fb, m_ip, "callpos");
				GET_VARIANT(*m_fb, m_bp, callpos, m_ip);
				m_ip++;

				int retnum = COMMAND_CODE(GET_CMD(*m_fb, m_ip));
				m_ip++;
				
				int retpos[MAX_FAKE_RETURN_NUM];

				for (int i = 0; i < retnum; i++)
				{
					assert(CHECK_STACK_POS(*m_fb, m_ip) || CHECK_CONTAINER_POS(*m_fb, m_ip));
					retpos[i] = m_ip;
					m_ip++;
				}
				
				int argnum = COMMAND_CODE(GET_CMD(*m_fb, m_ip));
				m_ip++;

				paramstack & ps = *getps(m_fk);
				PS_CLEAR(ps);
				for (int i = 0; i < argnum; i++)
				{
					variant * arg = 0;
					LOG_VARIANT(*m_fb, m_ip, "arg");
					GET_VARIANT(*m_fb, m_bp, arg, m_ip);
					m_ip++;

					variant * argdest = 0;
					PS_PUSH_AND_GET(ps, argdest);
					*argdest = *arg;
				}
				
				if (LIKE(calltype == CALL_NORMAL))
				{
					call(*callpos, retnum, retpos);
				}
				else if (LIKE(calltype == CALL_CLASSMEM))
				{
					void * classptr = 0;
					const char * classprefix = 0;

					// prefix
					variant * classvar;
					PS_GET(ps, classvar, PS_SIZE(ps) - 1);
					V_GET_POINTER(classvar, classptr, classprefix);

					if (UNLIKE(err))
					{
						break;
					}

					// mem func name
					const char * funcname = 0;
					V_GET_STRING(callpos, funcname);
					
					if (UNLIKE(err))
					{
						break;
					}

					if (UNLIKE(!classptr))
					{
						err = true;
						seterror(fk, efk_run_inter_error, fkgetcurfile(fk), fkgetcurline(fk), fkgetcurfunc(fk), "interpreter class mem call error, the class ptr is null, type %s", classprefix);
						break;
					}

					// whole name
					char wholename[MAX_FAKE_REG_FUNC_NAME_LEN];
					if (UNLIKE(classvar->data.ponter->typesz + callpos->data.str->sz >= MAX_FAKE_REG_FUNC_NAME_LEN))
					{
						err = true;
						seterror(fk, efk_run_inter_error, fkgetcurfile(fk), fkgetcurline(fk), fkgetcurfunc(fk), "interpreter class mem call error, the name is too long, func %s %s", classprefix, funcname);
						break;
					}
					memcpy(wholename, classprefix, classvar->data.ponter->typesz);
					memcpy(wholename + classvar->data.ponter->typesz, funcname, callpos->data.str->sz);
					wholename[classvar->data.ponter->typesz + callpos->data.str->sz] = 0;

					// call it
					variant tmp;
					V_SET_STRING(&tmp, wholename);

					call(tmp, retnum, retpos);
				}
				else
				{
					m_processor->start_routine(*callpos, retnum, retpos);
				}
			}
			break;
		case OPCODE_RETURN:
			{
				int returnnum = COMMAND_CODE(GET_CMD(*m_fb, m_ip));
				if (UNLIKE(!returnnum))
				{
					FKLOG("return empty");
					m_ip = (*m_fb).m_size;
					break;
				}
				m_ip++;

				// 塞给ret
				for (int i = 0; i < returnnum; i++)
				{
					const variant * ret = 0;
					LOG_VARIANT(*m_fb, m_ip, "ret");
					GET_VARIANT(*m_fb, m_bp, ret, m_ip);
					m_ip++;

					m_ret[i] = *ret;

					FKLOG("return %s", (vartostring(&m_ret[i])).c_str());
				}
				
				m_ip = (*m_fb).m_size;
			}
			break;
		case OPCODE_SLEEP:
			{
				const variant * time = 0;
				LOG_VARIANT(*m_fb, m_ip, "time");
				GET_VARIANT(*m_fb, m_bp, time, m_ip);
				m_ip++;

				uint32_t sleeptime = 0;
				V_GET_REAL(time, sleeptime);

				m_wakeuptime = fkgetmstick() + sleeptime;
				m_sleeping = true;
				return i + 1;
			}
			break;
		case OPCODE_YIELD:
			{
				const variant * time = 0;
				LOG_VARIANT(*m_fb, m_ip, "time");
				GET_VARIANT(*m_fb, m_bp, time, m_ip);
				m_ip++;

				V_GET_REAL(time, m_yieldtime);
				m_sleeping = true;
				return i + 1;
			}
			break;
		default:
			assert(0);
			FKERR("next err code %d %s", code, OpCodeStr(code));
			break;
		}
		
		if (UNLIKE(err))
		{
			// 发生错误
			m_isend = true;

			// 清除当前栈上函数的使用标记
			{
				int ip = m_ip;
				int bp = m_bp;
				const func_binary * fb = m_fb;

				while (!BP_END(bp))
				{
					// 标记
					FUNC_BINARY_USE(*fb)--;
					
					// 更新
					if (UNLIKE(!FUNC_BINARY_USE(*fb) && FUNC_BINARY_BACKUP(*fb)))
					{
						FUNC_BINARY_BACKUP_MOVE(*fb);
					}
					
					BP_GET_FB(bp, fb);
					BP_GET_IP(bp, ip);
					int callbp = 0;
					BP_GET_BP(bp, callbp);
					bp = callbp;
					if (BP_END(bp))
					{
						break;
					}
				}
			}
		}

		if (UNLIKE(m_isend))
		{
			break;
		}
		
		i++;
		
		if (UNLIKE(i >= cmdnum))
		{
			break;
		}
	}
	
	return i;
}
Ejemplo n.º 13
0
void debuging::debug()
{
	fake * fk = m_fk;
	bool isend = false;
	int range = 0;
	int command = debug_next;
	std::vector<String> paramvec;
	const char * lastfunc = 0;
	breakpoint_list blist;
	int bindex = 0;
	int frame = 0;
	int lastrid = fkgetcurroutineid(fk);
	int rid = lastrid;
	std::vector<String> watchvec;
	bool firsttime = true;
	while (1)
	{
		show_watch_variant(fk, rid, frame, watchvec);
		check_show_func_header(fk, rid, frame, lastrid, lastfunc);
		show_debug_code(fk, rid, frame, range);
FAKEINPUT:
		get_debug_command(fk, command, paramvec);
		switch (command)
		{
		case debug_next:
			{		
				frame = 0;
				rid = fkgetcurroutineid(fk);
						
				if (firsttime)
				{
					if (check_trigger_breakpoint(fk, blist))
					{
						firsttime = false;
						break;
					}
				}
				firsttime = false;
				
				const char * lastfile = fkgetcurfile(fk);
				int lastline = fkgetcurline(fk);
				int laststacklength = fkgetcurcallstacklength(fk);
				int lastrid = rid;
				const char * curfile = fkgetcurfile(fk);
				int curline = fkgetcurline(fk);
				int curstacklength = fkgetcurcallstacklength(fk);
				int currid = rid;
				while (currid == lastrid && 
					(curstacklength > laststacklength || 
					(strcmp(lastfile, curfile) == 0 && lastline == curline)))
				{
					resume(isend);
					if (isend)
					{
						break;
					}
					curfile = fkgetcurfile(fk);
					curline = fkgetcurline(fk);
					curstacklength = fkgetcurcallstacklength(fk);
					currid = fkgetcurroutineid(fk);
					if (check_trigger_breakpoint(fk, blist))
					{
						break;
					}
				}
				
				rid = fkgetcurroutineid(fk);
			}
			break;
		case debug_step:
			{
				frame = 0;
				rid = fkgetcurroutineid(fk);
				
				if (firsttime)
				{
					if (check_trigger_breakpoint(fk, blist))
					{
						firsttime = false;
						break;
					}
				}
				firsttime = false;
				
				const char * lastfile = fkgetcurfile(fk);
				int lastline = fkgetcurline(fk);
				int lastrid = rid;
				const char * curfile = fkgetcurfile(fk);
				int curline = fkgetcurline(fk);
				int currid = rid;
				while (currid == lastrid &&
					(strcmp(lastfile, curfile) == 0 && lastline == curline))
				{
					resume(isend);
					if (isend)
					{
						break;
					}
					curfile = fkgetcurfile(fk);
					curline = fkgetcurline(fk);
					currid = fkgetcurroutineid(fk);
					if (check_trigger_breakpoint(fk, blist))
					{
						break;
					}
				}
				
				rid = fkgetcurroutineid(fk);
			}
			break;
		case debug_next_instruction:
			{
				frame = 0;
				rid = fkgetcurroutineid(fk);
				
				if (firsttime)
				{
					if (check_trigger_breakpoint(fk, blist))
					{
						firsttime = false;
						break;
					}
				}
				firsttime = false;
				
				int laststacklength = fkgetcurcallstacklength(fk);
				int lastrid = rid;
				int curstacklength = fkgetcurcallstacklength(fk);
				int currid = rid;
				do
				{
					resume(isend);
					if (isend)
					{
						break;
					}
					curstacklength = fkgetcurcallstacklength(fk);
					currid = fkgetcurroutineid(fk);
					if (check_trigger_breakpoint(fk, blist))
					{
						break;
					}
				}
				while (currid == lastrid &&
					curstacklength > laststacklength);
					
				rid = fkgetcurroutineid(fk);
			}
			break;
		case debug_step_instruction:
			{
				frame = 0;
				rid = fkgetcurroutineid(fk);
				
				if (firsttime)
				{
					if (check_trigger_breakpoint(fk, blist))
					{
						firsttime = false;
						break;
					}
				}
				firsttime = false;
				
				resume(isend);
				
				rid = fkgetcurroutineid(fk);
				if (check_trigger_breakpoint(fk, blist))
				{
					break;
				}
			}
			break;
		case debug_continue:
			{
				frame = 0;
				rid = fkgetcurroutineid(fk);

				if (firsttime)
				{
					if (check_trigger_breakpoint(fk, blist))
					{
						firsttime = false;
						break;
					}
				}
				firsttime = false;
				
				while (1)
				{
					resume(isend);
					rid = fkgetcurroutineid(fk);
					if (check_trigger_breakpoint(fk, blist))
					{
						break;
					}
					if (isend)
					{
						break;
					}
				}
			}
			break;
		case debug_breakpoint:
			{
				breakpoint tmp;
				if (paramvec.empty())
				{
					tmp.file = fkgetcurfilebyroutinebyframe(fk, rid, frame);
					tmp.line = fkgetcurlinebyroutinebyframe(fk, rid, frame);
				}
				else
				{
					String str = paramvec[0];
					int subpos = str.find(':');
					if (subpos != -1)
					{
						String filestr = str.substr(0, subpos);
						String linestr = str.substr(subpos + 1);
						
						tmp.file = filestr;
						tmp.line = fkatoi(&linestr);
					}
					else
					{
						bool isnumber = true;
						for (int i = 0; i < (int)str.size(); i++)
						{
							if (!isdigit(str[i]))
							{
								isnumber = false;
								break;
							}
						}

						if (isnumber)
						{
							tmp.file = fkgetcurfilebyroutinebyframe(fk, rid, frame);
							tmp.line = fkatoi(&str);
						}
						else 
						{
							if (!fkisfunc(fk, str.c_str()))
							{
								printf("%s is not func\n", str.c_str());
								continue;
							}
							
							tmp.file = fkgetfuncfile(fk, str.c_str());
							tmp.line = fkgetfuncstartline(fk, str.c_str());
						}
					}
				}
				tmp.enable = true;
				tmp.id = bindex;
				
				if ((int)tmp.file.find_last_of('/') != -1)
				{
					tmp.file = tmp.file.substr(tmp.file.find_last_of('/') + 1);
				}
				
				blist.push_back(tmp);
				bindex++;
				printf("Breakpoint %d at file %s, line %d total %d\n", tmp.id, tmp.file.c_str(), tmp.line, (int)blist.size());
			}
			break;
		case debug_enable:
			{
				if (paramvec.empty())
				{
					for (int i = 0;  i < (int)blist.size(); i++)
					{
						breakpoint & tmp = blist[i];
						tmp.enable = true;
					}
				}
				else
				{
					int id = atoi(paramvec[0].c_str());
					for (int i = 0;  i < (int)blist.size(); i++)
					{
						breakpoint & tmp = blist[i];
						if (tmp.id == id)
						{
							tmp.enable = true;
						}
					}
				}
			}
			break;
		case debug_disable:
			{
				if (paramvec.empty())
				{
					for (int i = 0;  i < (int)blist.size(); i++)
					{
						breakpoint & tmp = blist[i];
						tmp.enable = false;
					}
				}
				else
				{
					int id = fkatoi(&paramvec[0]);
					for (int i = 0;  i < (int)blist.size(); i++)
					{
						breakpoint & tmp = blist[i];
						if (tmp.id == id)
						{
							tmp.enable = false;
						}
					}
				}
			}
			break;
		case debug_delete:
			{
				if (paramvec.empty())
				{
					blist.clear();
					watchvec.clear();
					continue;
				}
				else
				{
					int id = fkatoi(&paramvec[0]);
					for (int i = 0;  i < (int)blist.size(); i++)
					{
						breakpoint & tmp = blist[i];
						if (tmp.id == id)
						{
							blist.erase(blist.begin() + i);
						}
					}
				}
			}
			break;
		case debug_info:
			{
				if (paramvec.empty())
				{
					printf("need arg, useage: i b, i r\n");
					continue;
				}

				if (paramvec[0] == "b")
				{
					printf("Id\tEnb\twhere\n");
					for (int i = 0;  i < (int)blist.size(); i++)
					{
						breakpoint & tmp = blist[i];
						printf("%d\t%s\tfile %s, line %d\n", tmp.id, tmp.enable ? "y" : "n", tmp.file.c_str(), tmp.line);
					}
				}
				else if (paramvec[0] == "r")
				{
					for (int i = 0;  i < (int)fkgetcurroutinenum(fk); i++)
					{
						printf("%s%s%s\n", fkgetroutineidbyindex(fk, i) == rid ? "*" : "", 
							fkgetroutineidbyindex(fk, i) == fkgetcurroutineid(fk) ? "->" : "", 
							fkgetcurroutinebyindex(fk, i));
					}
				}
				
				printf("\n");
			}
			break;
		case debug_finish:
			{
				frame = 0;
				rid = fkgetcurroutineid(fk);
				
				int laststacklength = fkgetcurcallstacklength(fk);
				int curstacklength = fkgetcurcallstacklength(fk);
				do
				{
					resume(isend);
					if (isend)
					{
						break;
					}
					curstacklength = fkgetcurcallstacklength(fk);
				}
				while (curstacklength >= laststacklength);
			}
			break;
		case debug_list:
			{
				int listrange = 3;
				if (!paramvec.empty())
				{
					listrange = fkatoi(&paramvec[0]);
				}
				show_debug_code(fk, rid, frame, listrange);
				goto FAKEINPUT;
			}
			break;
		case debug_print:
			{
				if (paramvec.empty())
				{
					printf("need arg, useage: p variant\n");
					continue;
				}

				String name = paramvec[0];
				printf("%s\n", fkgetcurvaiantbyroutinebyframe(fk, rid, frame, name.c_str()));
			}
			break;
		case debug_set:
			{
				if (paramvec.size() < 2)
				{
					printf("need arg, useage: set variant value\n");
					continue;
				}

				String name = paramvec[0];
				String value = paramvec[1];
				fksetcurvaiantbyroutinebyframe(fk, rid, frame, name.c_str(), value.c_str());
				printf("%s\n", fkgetcurvaiantbyroutinebyframe(fk, rid, frame, name.c_str()));
			}
			break;
		case debug_watch:
			{
				if (paramvec.empty())
				{
					printf("need arg, useage: wa variant\n");
					continue;
				}

				String name = paramvec[0];
				watchvec.push_back(name);
			}
			break;
		case debug_backtrace:
			{
				int length = fkgetcurcallstacklengthbyroutine(fk, rid);
				for (int i = 0; i < length; i++)
				{
					printf("%s%s\n", i == frame ? "*" : " ", fkgetcurcallstackbyroutinebyframe(fk, rid, i));
				}
				goto FAKEINPUT;
			}
			break;
		case debug_frame:
			{
				if (paramvec.empty())
				{
					frame = 0;
				}
				else
				{
					int theframe = fkatoi(&paramvec[0]);
					if (theframe < 0 || theframe >= fkgetcurcallstacklengthbyroutine(fk, rid))
					{
						printf("%d is invalid\n", theframe);
					}
					frame = theframe;
				}
			}
			break;
		case debug_disa:
			{
				int pos = fkgetcurbytecodeposbyroutine(fk, rid);
				const char * func = fkgetcurfuncbyroutinebyframe(fk, rid, frame);
				printf("%s\n", fkdumpfunc(fk, func, pos));
			}
			break;
		case debug_routine:
			{
				if (paramvec.empty())
				{
					printf("need arg, useage: r rid\n");
					continue;
				}

				int id = fkatoi(&paramvec[0]);
				if (!fkishaveroutine(fk, id))
				{
					printf("no routine %d\n", id);
					continue;
				}
				
				rid = id;
			}
			break;
		default:
			continue;
		}
		if (isend)
		{
			break;
		}
	}
	printf("end\n");

	// ret
	{
		fkpsclear(fk);
		variant * ret = 0;
		bool err = false;
		PS_PUSH_AND_GET(fk->ps, ret);
		*ret = m_ret;
		CHECK_ERR(err);
	}
}