Lua opt.c (4.0.1)

/*
** $Id: opt.c,v 1.22 2000/10/31 16:57:23 lhf Exp $
** optimize bytecodes
** See Copyright Notice in lua.h
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "luac.h"

static int MapConstant(Hash* t, int j, const TObject* key)
{
 const TObject* o=luaH_get(L,t,key);
 if (ttype(o)==LUA_TNUMBER)
  return (int) nvalue(o);
 else
 {
  TObject val;
  ttype(&val)=LUA_TNUMBER;
  nvalue(&val)=j;
  *luaH_set(L,t,key)=val;
  LUA_ASSERT(j>=0,"MapConstant returns negative!");
  return j;
 }
}

static int MapConstants(Proto* tf, Hash* map)
{
 int i,j,k,n,m=0;
 TObject o;
 j=0; n=tf->nknum; ttype(&o)=LUA_TNUMBER;
 for (i=0; i<n; i++)
 {
  nvalue(&o)=tf->knum[i];
  k=MapConstant(map,j,&o);
  if (k==j) j++;
 }
 m=j;
 j=0; n=tf->nkstr; ttype(&o)=LUA_TSTRING;
 for (i=0; i<n; i++)
 {
  tsvalue(&o)=tf->kstr[i];
  k=MapConstant(map,j,&o);
  if (k==j) j++;
 }
 return m+j;
}

static void PackConstants(Proto* tf, Hash* map)
{
 int i,j,k,n;
 TObject o;
#ifdef DEBUG
 printf("%p before pack nknum=%d nkstr=%d\n",tf,tf->nknum,tf->nkstr);
#endif
 j=0; n=tf->nknum; ttype(&o)=LUA_TNUMBER;
 for (i=0; i<n; i++)
 {
  nvalue(&o)=tf->knum[i];
  k=MapConstant(map,-1,&o);
  if (k==j) tf->knum[j++]=tf->knum[i];
 }
 tf->nknum=j;
 j=0; n=tf->nkstr; ttype(&o)=LUA_TSTRING;
 for (i=0; i<n; i++)
 {
  tsvalue(&o)=tf->kstr[i];
  k=MapConstant(map,-1,&o);
  if (k==j) tf->kstr[j++]=tf->kstr[i];
 }
 tf->nkstr=j;
#ifdef DEBUG
 printf("%p after  pack nknum=%d nkstr=%d\n",tf,tf->nknum,tf->nkstr);
#endif
}

static void OptConstants(Proto* tf)
{
 Instruction* p;
 int n=tf->nknum+tf->nkstr;
 Hash* map=luaH_new(L,n);
 int m=MapConstants(tf,map);
#ifdef DEBUG
 printf("%p n=%d m=%d %s\n",tf,n,m,(m==n)?"nothing to optimize":"yes!");
#endif
 if (m==n) return;
 for (p=tf->code;; p++)
 {
  Instruction i=*p;
  int op=GET_OPCODE(i);
  switch (op)
  {
   TObject o;
   int j,k;
   case OP_PUSHNUM: case OP_PUSHNEGNUM:
    j=GETARG_U(i);
    ttype(&o)=LUA_TNUMBER; nvalue(&o)=tf->knum[j];
    k=MapConstant(map,-1,&o);
    if (k!=j) *p=CREATE_U(op,k);
    break;
   case OP_PUSHSTRING: case OP_GETGLOBAL: case OP_GETDOTTED:
   case OP_PUSHSELF:   case OP_SETGLOBAL:
    j=GETARG_U(i);
    ttype(&o)=LUA_TSTRING; tsvalue(&o)=tf->kstr[j];
    k=MapConstant(map,-1,&o);
    if (k!=j) *p=CREATE_U(op,k);
    break;
   case OP_END:
    PackConstants(tf,map);
    luaH_free(L,map);
    return;
   default:
    break;
  }
 }
}

#define OptFunction luaU_optchunk

void OptFunction(Proto* tf)
{
 int i,n=tf->nkproto;
 OptConstants(tf);
 for (i=0; i<n; i++) OptFunction(tf->kproto[i]);
}