/* ** Call a C function. ** Cstack.num is the number of arguments; Cstack.lua2C points to the ** first argument. Returns an index to the first result from C. */ static StkId callC (lua_CFunction f, StkId base) { struct C_Lua_Stack *cls = &L->Cstack; struct C_Lua_Stack oldCLS = *cls; StkId firstResult; int numarg = (L->stack.top-L->stack.stack) - base; cls->num = numarg; cls->lua2C = base; cls->base = base+numarg; /* == top-stack */ if (L->callhook) luaD_callHook(base, NULL, 0); (*f)(); /* do the actual call */ if (L->callhook) /* func may have changed callhook */ luaD_callHook(base, NULL, 1); firstResult = cls->base; *cls = oldCLS; return firstResult; }
/* ** Call a function (C or Lua). The function to be called is at *func. ** The arguments are on the stack, right after the function. ** When returns, the results are on the stack, starting at the original ** function position. ** The number of results is nResults, unless nResults=LUA_MULTRET. */ void luaD_call (lua_State *L, StkId func, int nResults) { lua_Hook callhook; StkId firstResult; CallInfo ci; Closure *cl; if (ttype(func) != LUA_TFUNCTION) { /* `func' is not a function; check the `function' tag method */ Closure *tm = luaT_gettmbyObj(L, func, TM_FUNCTION); if (tm == NULL) luaG_typeerror(L, func, "call"); luaD_openstack(L, func); clvalue(func) = tm; /* tag method is the new function to be called */ ttype(func) = LUA_TFUNCTION; } cl = clvalue(func); ci.func = cl; infovalue(func) = &ci; ttype(func) = LUA_TMARK; callhook = L->callhook; if (callhook) luaD_callHook(L, func, callhook, "call"); firstResult = (cl->isC ? callCclosure(L, cl, func+1) : luaV_execute(L, cl, func+1)); if (callhook) /* same hook that was active at entry */ luaD_callHook(L, func, callhook, "return"); LUA_ASSERT(ttype(func) == LUA_TMARK, "invalid tag"); /* move results to `func' (to erase parameters and function) */ if (nResults == LUA_MULTRET) { while (firstResult < L->top) /* copy all results */ *func++ = *firstResult++; L->top = func; } else { /* copy at most `nResults' */ for (; nResults > 0 && firstResult < L->top; nResults--) *func++ = *firstResult++; L->top = func; for (; nResults > 0; nResults--) { /* if there are not enough results */ ttype(L->top) = LUA_TNIL; /* adjust the stack */ incr_top; /* must check stack space */ } } luaC_checkGC(L); }
/* ** Execute the given opcode, until a RET. Parameters are between ** [stack+base,top). Returns n such that the the results are between ** [stack+n,top). */ StkId luaV_execute (struct CallInfo *ci) { /* Save index in case CallInfo array is realloc'd */ int32 ci_index = ci - L->base_ci; struct Stack *S = &L->stack; /* to optimize */ Closure *cl; TProtoFunc *tf; StkId base; Byte *pc; TObject *consts; newfunc: cl = L->ci->c; tf = L->ci->tf; base = L->ci->base; if (S->top-S->stack > base && ttype(S->stack+base) == LUA_T_LINE) base++; pc = L->ci->pc; consts = tf->consts; while (1) { int32 aux; switch ((OpCode)(aux = *pc++)) { case PUSHNIL0: ttype(S->top++) = LUA_T_NIL; break; case PUSHNIL: aux = *pc++; do { ttype(S->top++) = LUA_T_NIL; } while (aux--); break; case PUSHNUMBER: aux = *pc++; goto pushnumber; case PUSHNUMBERW: aux = next_word(pc); goto pushnumber; case PUSHNUMBER0: case PUSHNUMBER1: case PUSHNUMBER2: aux -= PUSHNUMBER0; pushnumber: ttype(S->top) = LUA_T_NUMBER; nvalue(S->top) = (real)aux; S->top++; break; case PUSHLOCAL: aux = *pc++; goto pushlocal; case PUSHLOCAL0: case PUSHLOCAL1: case PUSHLOCAL2: case PUSHLOCAL3: case PUSHLOCAL4: case PUSHLOCAL5: case PUSHLOCAL6: case PUSHLOCAL7: aux -= PUSHLOCAL0; pushlocal: *S->top++ = *((S->stack+base) + aux); break; case GETGLOBALW: aux = next_word(pc); goto getglobal; case GETGLOBAL: aux = *pc++; goto getglobal; case GETGLOBAL0: case GETGLOBAL1: case GETGLOBAL2: case GETGLOBAL3: case GETGLOBAL4: case GETGLOBAL5: case GETGLOBAL6: case GETGLOBAL7: aux -= GETGLOBAL0; getglobal: luaV_getglobal(tsvalue(&consts[aux])); break; case GETTABLE: luaV_gettable(); break; case GETDOTTEDW: aux = next_word(pc); goto getdotted; case GETDOTTED: aux = *pc++; goto getdotted; case GETDOTTED0: case GETDOTTED1: case GETDOTTED2: case GETDOTTED3: case GETDOTTED4: case GETDOTTED5: case GETDOTTED6: case GETDOTTED7: aux -= GETDOTTED0; getdotted: *S->top++ = consts[aux]; luaV_gettable(); break; case PUSHSELFW: aux = next_word(pc); goto pushself; case PUSHSELF: aux = *pc++; goto pushself; case PUSHSELF0: case PUSHSELF1: case PUSHSELF2: case PUSHSELF3: case PUSHSELF4: case PUSHSELF5: case PUSHSELF6: case PUSHSELF7: aux -= PUSHSELF0; pushself: { TObject receiver = *(S->top-1); *S->top++ = consts[aux]; luaV_gettable(); *S->top++ = receiver; break; } case PUSHCONSTANTW: aux = next_word(pc); goto pushconstant; case PUSHCONSTANT: aux = *pc++; goto pushconstant; case PUSHCONSTANT0: case PUSHCONSTANT1: case PUSHCONSTANT2: case PUSHCONSTANT3: case PUSHCONSTANT4: case PUSHCONSTANT5: case PUSHCONSTANT6: case PUSHCONSTANT7: aux -= PUSHCONSTANT0; pushconstant: *S->top++ = consts[aux]; break; case PUSHUPVALUE: aux = *pc++; goto pushupvalue; case PUSHUPVALUE0: case PUSHUPVALUE1: aux -= PUSHUPVALUE0; pushupvalue: *S->top++ = cl->consts[aux+1]; break; case SETLOCAL: aux = *pc++; goto setlocal; case SETLOCAL0: case SETLOCAL1: case SETLOCAL2: case SETLOCAL3: case SETLOCAL4: case SETLOCAL5: case SETLOCAL6: case SETLOCAL7: aux -= SETLOCAL0; setlocal: *((S->stack+base) + aux) = *(--S->top); break; case SETGLOBALW: aux = next_word(pc); goto setglobal; case SETGLOBAL: aux = *pc++; goto setglobal; case SETGLOBAL0: case SETGLOBAL1: case SETGLOBAL2: case SETGLOBAL3: case SETGLOBAL4: case SETGLOBAL5: case SETGLOBAL6: case SETGLOBAL7: aux -= SETGLOBAL0; setglobal: luaV_setglobal(tsvalue(&consts[aux])); break; case SETTABLE0: luaV_settable(S->top-3, 1); break; case SETTABLE: luaV_settable(S->top-3-(*pc++), 2); break; case SETLISTW: aux = next_word(pc); aux *= LFIELDS_PER_FLUSH; goto setlist; case SETLIST: aux = *(pc++) * LFIELDS_PER_FLUSH; goto setlist; case SETLIST0: aux = 0; setlist: { int32 n = *(pc++); TObject *arr = S->top-n-1; for (; n; n--) { ttype(S->top) = LUA_T_NUMBER; nvalue(S->top) = (real)(n+aux); *(luaH_set(avalue(arr), S->top)) = *(S->top-1); S->top--; } break; } case SETMAP0: aux = 0; goto setmap; case SETMAP: aux = *pc++; setmap: { TObject *arr = S->top-(2*aux)-3; do { *(luaH_set(avalue(arr), S->top-2)) = *(S->top-1); S->top-=2; } while (aux--); break; } case POP: aux = *pc++; goto pop; case POP0: case POP1: aux -= POP0; pop: S->top -= (aux+1); break; case CREATEARRAYW: aux = next_word(pc); goto createarray; case CREATEARRAY0: case CREATEARRAY1: aux -= CREATEARRAY0; goto createarray; case CREATEARRAY: aux = *pc++; createarray: luaC_checkGC(); avalue(S->top) = luaH_new(aux); ttype(S->top) = LUA_T_ARRAY; S->top++; break; case EQOP: case NEQOP: { int32 res = luaO_equalObj(S->top-2, S->top-1); S->top--; if (aux == NEQOP) res = !res; ttype(S->top-1) = res ? LUA_T_NUMBER : LUA_T_NIL; nvalue(S->top-1) = 1; break; } case LTOP: comparison(LUA_T_NUMBER, LUA_T_NIL, LUA_T_NIL, IM_LT); break; case LEOP: comparison(LUA_T_NUMBER, LUA_T_NUMBER, LUA_T_NIL, IM_LE); break; case GTOP: comparison(LUA_T_NIL, LUA_T_NIL, LUA_T_NUMBER, IM_GT); break; case GEOP: comparison(LUA_T_NIL, LUA_T_NUMBER, LUA_T_NUMBER, IM_GE); break; case ADDOP: { TObject *l = S->top-2; TObject *r = S->top-1; if (tonumber(r) || tonumber(l)) call_arith(IM_ADD); else { nvalue(l) += nvalue(r); --S->top; } break; } case SUBOP: { TObject *l = S->top-2; TObject *r = S->top-1; if (tonumber(r) || tonumber(l)) call_arith(IM_SUB); else { nvalue(l) -= nvalue(r); --S->top; } break; } case MULTOP: { TObject *l = S->top-2; TObject *r = S->top-1; if (tonumber(r) || tonumber(l)) call_arith(IM_MUL); else { nvalue(l) *= nvalue(r); --S->top; } break; } case DIVOP: { TObject *l = S->top-2; TObject *r = S->top-1; if (tonumber(r) || tonumber(l)) call_arith(IM_DIV); else { nvalue(l) /= nvalue(r); --S->top; } break; } case POWOP: call_binTM(IM_POW, "undefined operation"); break; case CONCOP: { TObject *l = S->top-2; TObject *r = S->top-1; if (tostring(l) || tostring(r)) call_binTM(IM_CONCAT, "unexpected type for concatenation"); else { tsvalue(l) = strconc(tsvalue(l), tsvalue(r)); --S->top; } luaC_checkGC(); break; } case MINUSOP: if (tonumber(S->top-1)) { ttype(S->top) = LUA_T_NIL; S->top++; call_arith(IM_UNM); } else nvalue(S->top-1) = - nvalue(S->top-1); break; case NOTOP: ttype(S->top-1) = (ttype(S->top-1) == LUA_T_NIL) ? LUA_T_NUMBER : LUA_T_NIL; nvalue(S->top-1) = 1; break; case ONTJMPW: aux = next_word(pc); goto ontjmp; case ONTJMP: aux = *pc++; ontjmp: if (ttype(S->top-1) != LUA_T_NIL) pc += aux; else S->top--; break; case ONFJMPW: aux = next_word(pc); goto onfjmp; case ONFJMP: aux = *pc++; onfjmp: if (ttype(S->top-1) == LUA_T_NIL) pc += aux; else S->top--; break; case JMPW: aux = next_word(pc); goto jmp; case JMP: aux = *pc++; jmp: pc += aux; break; case IFFJMPW: aux = next_word(pc); goto iffjmp; case IFFJMP: aux = *pc++; iffjmp: if (ttype(--S->top) == LUA_T_NIL) pc += aux; break; case IFTUPJMPW: aux = next_word(pc); goto iftupjmp; case IFTUPJMP: aux = *pc++; iftupjmp: if (ttype(--S->top) != LUA_T_NIL) pc -= aux; break; case IFFUPJMPW: aux = next_word(pc); goto iffupjmp; case IFFUPJMP: aux = *pc++; iffupjmp: if (ttype(--S->top) == LUA_T_NIL) pc -= aux; break; case CLOSURE: aux = *pc++; goto closure; case CLOSURE0: aux = 0; goto closure; case CLOSURE1: aux = 1; closure: luaV_closure(aux); luaC_checkGC(); break; case CALLFUNC: aux = *pc++; goto callfunc; case CALLFUNC0: case CALLFUNC1: aux -= CALLFUNC0; callfunc: { StkId newBase = (S->top-S->stack)-(*pc++); TObject *func = S->stack+newBase-1; L->ci->pc = pc; if (ttype(func) == LUA_T_PROTO || (ttype(func) == LUA_T_CLOSURE && ttype(&clvalue(func)->consts[0]) == LUA_T_PROTO)) { /* Calling another Lua function */ luaD_precall(func, newBase, aux); ttype(func) = (ttype(func) == LUA_T_PROTO) ? LUA_T_PMARK : LUA_T_CLMARK; goto newfunc; } luaD_call(newBase, aux); if (L->Tstate != RUN) { if (ci_index > 1) /* C functions detected by break_here */ lua_error("Cannot yield through method call"); return -1; } break; } case ENDCODE: S->top = S->stack + base; /* goes through */ case RETCODE: { StkId firstResult = (base + ((aux==RETCODE) ? *pc : 0)); if (lua_callhook) luaD_callHook(base, NULL, 1); /* If returning from the original stack frame, terminate */ if (L->ci == L->base_ci + ci_index) return firstResult; luaD_postret(firstResult); goto newfunc; } case SETLINEW: aux = next_word(pc); goto setline; case SETLINE: aux = *pc++; setline: if ((S->stack+base-1)->ttype != LUA_T_LINE) { /* open space for LINE value */ luaD_openstack((S->top-S->stack)-base); base++; (S->stack+base-1)->ttype = LUA_T_LINE; } (S->stack+base-1)->value.i = aux; if (lua_linehook) luaD_lineHook(aux); break; #ifdef DEBUG default: LUA_INTERNALERROR("opcode doesn't match"); #endif } } }