text: /*
  ** $Id: lfunc.c,v 2.45.1.1 2017/04/19 17:39:34 roberto Exp $
  ** Auxiliary functions to manipulate prototypes and closures
  ** See Copyright Notice in lua.h
  */
  
  #define lfunc_c
  #define LUA_CORE
  
  #include "lprefix.h"
  
  
  #include <stddef.h>
  
  #include "lua.h"
  
  #include "lfunc.h"
  #include "lgc.h"
  #include "lmem.h"
  #include "lobject.h"
  #include "lstate.h"
  
  
  
  CClosure *luaF_newCclosure (lua_State *L, int n) {
    GCObject *o = luaC_newobj(L, LUA_TCCL, sizeCclosure(n));
    CClosure *c = gco2ccl(o);
    c->nupvalues = cast_byte(n);
    return c;
  }
  
  
  LClosure *luaF_newLclosure (lua_State *L, int n) {
    GCObject *o = luaC_newobj(L, LUA_TLCL, sizeLclosure(n));
    LClosure *c = gco2lcl(o);
    c->p = NULL;
    c->nupvalues = cast_byte(n);
    while (n--) c->upvals[n] = NULL;
    return c;
  }
  
  /*
  ** fill a closure with new closed upvalues
  */
  void luaF_initupvals (lua_State *L, LClosure *cl) {
    int i;
    for (i = 0; i < cl->nupvalues; i++) {
      UpVal *uv = luaM_new(L, UpVal);
      uv->refcount = 1;
      uv->v = &uv->u.value;  /* make it closed */
      setnilvalue(uv->v);
      cl->upvals[i] = uv;
    }
  }
  
  
  UpVal *luaF_findupval (lua_State *L, StkId level) {
    UpVal **pp = &L->openupval;
    UpVal *p;
    UpVal *uv;
    lua_assert(isintwups(L) || L->openupval == NULL);
    while (*pp != NULL && (p = *pp)->v >= level) {
      lua_assert(upisopen(p));
      if (p->v == level)  /* found a corresponding upvalue? */
        return p;  /* return it */
      pp = &p->u.open.next;
    }
    /* not found: create a new upvalue */
    uv = luaM_new(L, UpVal);
    uv->refcount = 0;
    uv->u.open.next = *pp;  /* link it to list of open upvalues */
    uv->u.open.touched = 1;
    *pp = uv;
    uv->v = level;  /* current value lives in the stack */
    if (!isintwups(L)) {  /* thread not in list of threads with upvalues? */
      L->twups = G(L)->twups;  /* link it to the list */
      G(L)->twups = L;
    }
    return uv;
  }
  
  
  void luaF_close (lua_State *L, StkId level) {
    UpVal *uv;
    while (L->openupval != NULL && (uv = L->openupval)->v >= level) {
      lua_assert(upisopen(uv));
      L->openupval = uv->u.open.next;  /* remove from 'open' list */
      if (uv->refcount == 0)  /* no references? */
        luaM_free(L, uv);  /* free upvalue */
      else {
        setobj(L, &uv->u.value, uv->v);  /* move value to upvalue slot */
        uv->v = &uv->u.value;  /* now current value lives here */
        luaC_upvalbarrier(L, uv);
      }
    }
  }
  
  /* LUA_HALT { */
  /*
  #include <assert.h>
  void check_protolist(global_State* g, Proto* p)
  {
  if (p == NULL) return;
  
  if (p->list_prev == NULL) {
  assert(g->proto_list == p);
  }
  else {
  assert(p->list_prev->list_next == p);
  }
  
  if (p->list_next == NULL)	{
  // OK
  }
  else {
  assert(p->list_next->list_prev == p);
  check_protolist(g, p->list_next);
  }
  }
  */
  /* LUA_HALT } */
  
  Proto *luaF_newproto (lua_State *L) {
    GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto));
    Proto *f = gco2p(o);
    f->k = NULL;
    f->sizek = 0;
    f->p = NULL;
    f->sizep = 0;
    f->code = NULL;
    f->cache = NULL;
    f->sizecode = 0;
    f->lineinfo = NULL;
    f->sizelineinfo = 0;
    f->upvalues = NULL;
    f->sizeupvalues = 0;
    f->numparams = 0;
    f->is_vararg = 0;
    f->maxstacksize = 0;
    f->locvars = NULL;
    f->sizelocvars = 0;
    f->linedefined = 0;
    f->lastlinedefined = 0;
    f->source = NULL;
    /* LUA_HALT { */
    f->halts = NULL;
    f->sizehalts = 0;
    f->list_prev = NULL;
    f->list_next = L->l_G->proto_list;
    L->l_G->proto_list = f;
    if (f->list_next != NULL)
    {
  	  f->list_next->list_prev = f;
    }
    //check_protolist(L->l_G, L->l_G->proto_list);
    /* LUA_HALT } */
    return f;
  }
  
  
  void luaF_freeproto (lua_State *L, Proto *f) {
  	/* LUA_HALT { */
  	//check_protolist(L->l_G, f);
  	if (f->list_prev) {
  		f->list_prev->list_next = f->list_next;
  	}
  	else {
  		L->l_G->proto_list = f->list_next;
  	}
  	if (f->list_next) {
  		f->list_next->list_prev = f->list_prev;
  	}
  	//check_protolist(L->l_G, L->l_G->proto_list);
  	luaM_freearray(L, f->halts, f->sizehalts);
  	/* LUA_HALT } */
    luaM_freearray(L, f->code, f->sizecode);
    luaM_freearray(L, f->p, f->sizep);
    luaM_freearray(L, f->k, f->sizek);
    luaM_freearray(L, f->lineinfo, f->sizelineinfo);
    luaM_freearray(L, f->locvars, f->sizelocvars);
    luaM_freearray(L, f->upvalues, f->sizeupvalues);
    luaM_free(L, f);
  }
  
  
  /*
  ** Look for n-th local variable at line 'line' in function 'func'.
  ** Returns NULL if not found.
  */
  const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
    int i;
    for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) {
      if (pc < f->locvars[i].endpc) {  /* is variable active? */
        local_number--;
        if (local_number == 0)
          return getstr(f->locvars[i].varname);
      }
    }
    return NULL;  /* not found */
  }
  
  