Limite do código de um método é de 65535 bytes? [RESOLVIDO]

10 respostas
ctdaa

Olá.
Estou criando um parser com a ferramenta javaCC, que por sua vez gera várias classes java. Em uma destas classes geradas estou recebendo o seguinte erro:

Pesquisei o problema e a recomendação diz que este é um limite do java e que eu devo rever a gramática que estou implementando para otimizá-la.
Tudo bem, vou fazer isto. Mas este limite é fixo ou existe forma de configurar algum parametro de compilação ou algo assim?

10 Respostas

ViniGodoy

Sim, é fixo. E que eu saiba não existe.

Marky.Vasconcelos

Se seu método é maior que isso talvez seja uma boa hora de refatorar.

ctdaa

Existe alguma ferramenta, utilitário, plugin, etc… que possa fazer um refactor, clean-up ou algo parecido com o fonte ou com o código java compilado?
A intensão é somente reduzir o tamanho do código, já que a manutenção dos fontes não será feita diretamente no java (e sim pelo javaCC).

J

eu não sabia que existia esse limite. Mas um método com mais 65000 bytes também é exorbitante.

ctdaa

Como disse no início do tópico a classe é gerada automaticamente, por isso não posso dar manutenção direta no fonte. Quando eu compilar novamente a definição do javaCC ele vai regerar as classes e consequentemente perderá as alterações. Se houver uma ferramenta de refactor automatico, aplico novamente toda vez que forem regeradas.

E

Perguntinha. Digamos que seu método esteja gerando uma grande quantidade de bytecodes porque ele contém uma grande quantidade de constantes string. Seria possível acumular essas strings e lê-las de um resource, em vez de estarem no arquivo .class?

ctdaa

Boa idéia. Já havia pensado nisto. Mas examinei o fonte e não tem nenhuma string… quem projetou o compilador javaCC já deve ter pensado neste tipo de otimização… :frowning:

Vou colocar parte do fonte para ilustrar:
Os números que aparecem apontam para o código definido em uma classe de constantes.

private int jjMoveNfa_0(int startState, int curPos)
{
   int startsAt = 0;
   jjnewStateCnt = 1230;
   int i = 1;
   jjstateSet[0] = startState;
   int kind = 0x7fffffff;
   for (;;)
   {
      if (++jjround == 0x7fffffff)
         ReInitRounds();
      if (curChar < 64)
      {
         long l = 1L << curChar;
         do
         {
            switch(jjstateSet[--i])
            {
               case 922:
               case 496:
                  if ((0x3ff400000000000L & l) == 0L)
                     break;
                  if (kind > 192)
                     kind = 192;
                  jjCheckNAdd(496);
                  break;
               case 62:
                  if ((0x3ff400000000000L & l) == 0L)
                     break;
                  if (kind > 192)
                     kind = 192;
                  jjCheckNAdd(496);
                  break;
               case 193:
                  if ((0x3ff400000000000L & l) == 0L)
                     break;
                  if (kind > 192)
                     kind = 192;
                  jjCheckNAdd(496);
                  break;
               case 739:
                  if ((0x3ff400000000000L & l) == 0L)
                     break;
                  if (kind > 192)
                     kind = 192;
                  jjCheckNAdd(496);
                  break;
               case 405:
                  if ((0x3ff400000000000L & l) == 0L)
                     break;
                  if (kind > 192)
                     kind = 192;
                  jjCheckNAdd(496);
                  break;
               case 1098:
                  if ((0x3ff400000000000L & l) == 0L)
                     break;
                  if (kind > 192)
                     kind = 192;
                  jjCheckNAdd(496);
                  break;
               case 254:
                  if ((0x3ff400000000000L & l) == 0L)
                     break;
                  if (kind > 192)
                     kind = 192;
                  jjCheckNAdd(496);
                  break;
.....
               default : break;
            }
         } while(i != startsAt);
      }
      else if (curChar < 128)
      {
         long l = 1L << (curChar & 077);
         do
         {
            switch(jjstateSet[--i])
            {
               case 922:
                  if ((0x7fffffe07fffffeL & l) != 0L)
                  {
                     if (kind > 192)
                        kind = 192;
                     jjCheckNAdd(496);
                  }
                  if (curChar == 68)
                     jjstateSet[jjnewStateCnt++] = 921;
                  break;
               case 62:
                  if ((0x7fffffe07fffffeL & l) != 0L)
                  {
                     if (kind > 192)
                        kind = 192;
                     jjCheckNAdd(496);
                  }
                  if (curChar == 88)
                     jjstateSet[jjnewStateCnt++] = 145;
                  else if (curChar == 77)
                     jjstateSet[jjnewStateCnt++] = 138;
                  else if (curChar == 82)
                     jjstateSet[jjnewStateCnt++] = 136;
                  else if (curChar == 83)
                     jjstateSet[jjnewStateCnt++] = 113;
                  else if (curChar == 69)
                     jjstateSet[jjnewStateCnt++] = 90;
                  else if (curChar == 78)
                     jjstateSet[jjnewStateCnt++] = 76;
                  if (curChar == 88)
                     jjstateSet[jjnewStateCnt++] = 129;
                  else if (curChar == 78)
                     jjstateSet[jjnewStateCnt++] = 74;
                  else if (curChar == 82)
                     jjstateSet[jjnewStateCnt++] = 64;
                  if (curChar == 88)
                     jjstateSet[jjnewStateCnt++] = 110;
                  else if (curChar == 82)
                     jjstateSet[jjnewStateCnt++] = 61;
                  if (curChar == 88)
                     jjstateSet[jjnewStateCnt++] = 99;
                  if (curChar == 88)
                     jjstateSet[jjnewStateCnt++] = 96;
                  if (curChar == 88)
                     jjstateSet[jjnewStateCnt++] = 88;
                  break;
               case 193:
.....
ctdaa

Fiz uma intervenção manual que resolve provisoriamente o problema. Se alguém souber de uma solução melhor, agradeço.

//
// incluir este novo método:
private Integer[] firstSwitch(int i, int kind, long l)
{
// mover o primeiro switch do original para o novo método
    switch(jjstateSet[--i])
          case ...
          case ...
          case ...
...
          break;
       default : break;
    }
// incluir retorno de variáveis alteradas:
    Integer[] resultSet = new Integer[2];
    resultSet[0]=i;
    resultSet[1]=kind;
    return resultSet;
}

// no método original:
// substituir linhas do switch por:
         do
         { 
           // switch era neste bloco
           resultSet=firstSwitch(i, kind, l);
           i=resultSet[0];
           kind=resultSet[1];
         } while(i != startsAt);
    
//
fabiofalci

Olhando rapidamente no google há dicas para usar javaCC de uma forma mais eficiente.
Como esse post http://markmail.org/message/ztzrnyhkhnoai5uk que leva a essa url
http://javacc.dev.java.net/doc/lexertips.html

Ali deve ter dicas para solucionar o teu caso. O problema é que parece estar fora do ar.

ctdaa

Para registrar uma solução mais inteligente:
Como o problema era com a quantidade de palavras reservadas existentes na gramática, implementei uma segmentação separando alguns statements em um parser independente. No parser principal aciono o parser segundário quando o token específico for encontrado…
Alterei a definição do token () para capturar a linha completa do statement ( e não apenas a palavra DEFINE ):

<DEFAULT> TOKEN :
{
  < ALTER:         "ALTER"  >
| < BACKUP:      ( "BACKUP" | "BUP" ) >
| < BLDINDEX:    ( "BLDINDEX" | "BIX" ) >
| < CANCEL:        "CANCEL" >
| < REPRO:         "REPRO"  >
//* Statements implementados em parser externo:
| < DEFINE:      ( "DEFINE" | "DEF" ) (~[])(~["\n","\r"])* >

A chamada ao parser secundário (IdcamsDefine) dentro do parser principal (Idcams) ficou assim:

/////////////////////////////////
// Statement DEFINE
/////////////////////////////////
void statmDEFINE() :
{ Token t;
  String value;
  IdcamsDefine parser;
}
{
 t=< DEFINE >
 { Logger.getLogger("Parser").log(Level.FINE, "DEFINE"); }
 { value=t.image;
   parser = new IdcamsDefine(new ByteArrayInputStream(value.getBytes()));
   try {
	 parser.input();
   } catch (com.parser.idcams.define.ParseException e) {
 	  e.printStackTrace();
   }
 }
}
Criado 15 de outubro de 2009
Ultima resposta 23 de out. de 2009
Respostas 10
Participantes 6