第二人生的源码分析(112)脚本的综合分析(2)

系统 1709 0
 

前面介绍了分析脚本类的声明,下面来仔细地分析它的实现代码,理解它的实现过程,也就理解了脚本代码的编译过程,如下:

 

返回生成的代码大小为 0.

#001   S32 LLScriptScript::getSize()

#002   {

#003      return 0;

#004   }

#005  

 

脚本类的构造函数,主要进行初始化的工作。

#006   LLScriptScript::LLScriptScript(LLScritpGlobalStorage *globals,

#007                                  LLScriptState *states) :

#008       LLScriptFilePosition(0, 0),

#009      mStates(states), mGlobalScope(NULL), mGlobals(NULL), mGlobalFunctions(NULL), mGodLike(FALSE)

#010   {

 

设置缺省生成字节码的文件名称。

#011      const char DEFAULT_BYTECODE_FILENAME[] = "lscript.lso";

#012      strncpy(mBytecodeDest, DEFAULT_BYTECODE_FILENAME, sizeof(mBytecodeDest) -1); /*Flawfinder: ignore*/

#013      mBytecodeDest[MAX_STRING-1] = '/0';

 

下面开始分析全局变量和全局函数的保存位置。

#014      LLScriptGlobalVariable   *tvar;

#015      LLScriptGlobalFunctions *tfunc;

#016      LLScritpGlobalStorage *temp;

#017  

#018      temp = globals;

#019      while(temp)

#020      {

#021          if (temp->mbGlobalFunction)

#022          {

#023              if (!mGlobalFunctions)

#024              {

#025                  mGlobalFunctions = (LLScriptGlobalFunctions *)temp->mGlobal;

#026              }

#027              else

#028              {

#029                  tfunc = mGlobalFunctions;

#030                  while(tfunc->mNextp)

#031                  {

#032                      tfunc = tfunc->mNextp;

#033                  }

#034                  tfunc->mNextp = (LLScriptGlobalFunctions *)temp->mGlobal;

#035              }

#036          }

#037          else

#038          {

#039              if (!mGlobals)

#040              {

#041                  mGlobals = (LLScriptGlobalVariable *)temp->mGlobal;

#042              }

#043              else

#044              {

#045                  tvar = mGlobals;

#046                  while(tvar->mNextp)

#047                  {

#048                      tvar = tvar->mNextp;

#049                  }

#050                  tvar->mNextp = (LLScriptGlobalVariable *)temp->mGlobal;

#051              }

#052          }

#053          temp = temp->mNextp;

#054      }

#055   }

#056  

 

这个函数主要实现设置字节码保存的文件名称。

#057   void LLScriptScript::setBytecodeDest(const char* dst_filename)

#058   {

#059      strncpy(mBytecodeDest, dst_filename, MAX_STRING);   /*Flawfinder: ignore*/

#060      mBytecodeDest[MAX_STRING-1] = '/0';

#061   }

#062  

 

#063   void print_cil_globals(FILE* fp, LLScriptGlobalVariable* global)

#064   {

#065      fprintf(fp, ".field private ");

#066      print_cil_type(fp, global->mType->mType);

#067      fprintf(fp, " ");

#068      fprintf(fp, global->mIdentifier->mName);         /*Flawfinder: ignore*/

#069      fprintf(fp, "/n");

#070      if(NULL != global->mNextp)

#071      {

#072          print_cil_globals(fp, global->mNextp);

#073      }

#074   }

#075

 

开始递归处理所有脚本树。

#076   void LLScriptScript::recurse(FILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type,

#077   LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata)

#078   {

 

如果分析有出错,就不再处理。

#079      if (gErrorToText.getErrors())

#080      {

#081          return;

#082      }

 

根据不同的编译遍来作不同的树遍历处理。

#083      switch(pass)

#084      {

 

输出合适的说明文字。

#085      case LSCP_PRETTY_PRINT:

#086          if (mGlobals)

#087          {

#088              fdotabs(fp, tabs, tabsize);

#089              mGlobals->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount,

#090   NULL);

#091          }

#092  

#093          if (mGlobalFunctions)

#094          {

#095              fdotabs(fp, tabs, tabsize);

#096              mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry,

#097   entrycount, NULL);

#098          }

#099  

#100          fdotabs(fp, tabs, tabsize);

#101          mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);

#102          break;

 

进行代码优化,主要删除不需要的代码。

#103      case LSCP_PRUNE:

#104          if (mGlobalFunctions)

#105          {

#106              mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry,

#107   entrycount, NULL);

#108          }

#109          mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);

#110          break;

 

全局的作用域检查。

#111      case LSCP_SCOPE_PASS1:

#112          {

#113              mGlobalScope = new LLScriptScope(gScopeStringTable);

#114              // zeroth, add library functions to global scope

#115              S32 i;

#116              char *arg;

#117              LLScriptScopeEntry *sentry;

#118              for (i = 0; i < gScriptLibrary.mNextNumber; i++)

#119              {

#120                  // First, check to make sure this isn't a god only function, or that the viewer's agent is a god.

#121                  if (!gScriptLibrary.mFunctions[i]->mGodOnly || mGodLike)

#122                  {

#123                      if (gScriptLibrary.mFunctions[i]->mReturnType)

#124                          sentry = mGlobalScope->addEntry(gScriptLibrary.mFunctions[i]->mName,

#125   LIT_LIBRARY_FUNCTION, char2type(*gScriptLibrary.mFunctions[i]->mReturnType));

#126                      else

#127                          sentry = mGlobalScope->addEntry(gScriptLibrary.mFunctions[i]->mName,

#128   LIT_LIBRARY_FUNCTION, LST_NULL);

#129                      sentry->mLibraryNumber = i;

#130                      arg = gScriptLibrary.mFunctions[i]->mArgs;

#131                      if (arg)

#132                      {

#133                          while (*arg)

#134                          {

#135                              sentry->mFunctionArgs.addType(char2type(*arg));

#136                              sentry->mSize += LSCRIPTDataSize[char2type(*arg)];

#137                              sentry->mOffset += LSCRIPTDataSize[char2type(*arg)];

#138                              arg++;

#139                          }

#140                      }

#141                  }

#142              }

#143              // first go and collect all the global variables

#144              if (mGlobals)

#145                  mGlobals->recurse(fp, tabs, tabsize, pass, ptype, prunearg, mGlobalScope, type, basetype, count, chunk, heap,

#146   stacksize, entry, entrycount, NULL);

#147              // second, do the global functions

#148              if (mGlobalFunctions)

#149                  mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, mGlobalScope, type, basetype, count, chunk, heap,

#150   stacksize, entry, entrycount, NULL);

#151              // now do states

#152              mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, mGlobalScope, type, basetype, count, chunk, heap, stacksize, entry,

#153   entrycount, NULL);

#154              break;

#155          }

 

第二次作用域检查,主要检查跳转、函数调用和状态转换。

#156      case LSCP_SCOPE_PASS2:

#157          // now we're checking jumps, function calls, and state transitions

#158          if (mGlobalFunctions)

#159              mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, mGlobalScope, type, basetype, count, chunk, heap, stacksize, entry,

#160   entrycount, NULL);

#161          mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, mGlobalScope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);

#162          break;

 

对脚本的类型进行检查。

#163      case LSCP_TYPE:

#164          // first we need to check global variables

#165          if (mGlobals)

#166              mGlobals->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount,

#167   NULL);

#168          // now do global functions and states

#169          if (mGlobalFunctions)

#170              mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry,

#171   entrycount, NULL);

#172          mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);

#173          break;

 

确定所有脚本需的资源大小。

#174      case LSCP_RESOURCE:

#175          // first determine resource counts for globals

#176          count = 0;

#177          if (mGlobals)

#178              mGlobals->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount,

#179   NULL);

#180          // now do locals

#181          if (mGlobalFunctions)

#182              mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry,

#183   entrycount, NULL);

#184          mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);

#185          break;

 

输出汇编代码。

#186      case LSCP_EMIT_ASSEMBLY:

#187  

#188          if (mGlobals)

#189          {

#190              fprintf(fp, "GLOBALS/n");

#191              fdotabs(fp, tabs, tabsize);

#192              mGlobals->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount,

#193   NULL);

#194              fprintf(fp, "/n");

#195          }

#196  

#197          if (mGlobalFunctions)

#198          {

#199              fprintf(fp, "GLOBAL FUNCTIONS/n");

#200              fdotabs(fp, tabs, tabsize);

#201              mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry,

#202   entrycount, NULL);

#203              fprintf(fp, "/n");

#204          }

#205  

#206          fprintf(fp, "STATES/n");

#207          fdotabs(fp, tabs, tabsize);

#208          mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);

#209          fprintf(fp, "/n");

#210          break;

 

输出虚拟机可以运行的字节码。

#211      case LSCP_EMIT_BYTE_CODE:

#212          {

#213              // first, create data structure to hold the whole shebang

#214              LLScriptScriptCodeChunk *code = new LLScriptScriptCodeChunk(TOP_OF_MEMORY);

#215  

#216              // ok, let's add the registers, all zeroes for now

#217              S32 i;

#218              S32 nooffset = 0;

#219  

#220              for (i = LREG_IP; i < LREG_EOF; i++)

#221              {

#222                  if (i < LREG_NCE)

#223                      code->mRegisters->addBytes(4);

#224                  else if (LSL2_CURRENT_MAJOR_VERSION == LSL2_MAJOR_VERSION_TWO)

#225                      code->mRegisters->addBytes(8);

#226              }

#227              // global variables

#228              if (mGlobals)

#229                  mGlobals->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, code->mGlobalVariables,

#230   code->mHeap, stacksize, entry, entrycount, NULL);

#231  

#232              // put the ending heap block onto the heap

#233              U8 *temp;

#234              S32 size = lsa_create_data_block(&temp, NULL, 0);

#235              code->mHeap->addBytes(temp, size);

#236              delete [] temp;

#237  

#238              // global functions

#239              // make space for global function jump table

#240              if (mGlobalFunctions)

#241              {

#242              code->mGlobalFunctions->addBytes(LSCRIPTDataSize[LST_INTEGER]*mGlobalScope->mFunctionCount +

#243   LSCRIPTDataSize[LST_INTEGER]);

#244                  integer2bytestream(code->mGlobalFunctions->mCodeChunk, nooffset, mGlobalScope->mFunctionCount);

#245                  mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, code-

#246   >mGlobalFunctions, NULL, stacksize, entry, entrycount, NULL);

#247              }

#248  

#249  

#250              nooffset = 0;

#251              // states

#252              // make space for state jump/info table

#253              if (LSL2_CURRENT_MAJOR_VERSION == LSL2_MAJOR_VERSION_TWO)

#254              {

#255              code->mStates->addBytes(LSCRIPTDataSize[LST_INTEGER]*3*mGlobalScope->mStateCount + LSCRIPTDataSize

#256   [LST_INTEGER]);

#257              }

#258              else

#259              {

#260              code->mStates->addBytes(LSCRIPTDataSize[LST_INTEGER]*2*mGlobalScope->mStateCount + LSCRIPTDataSize

#261   [LST_INTEGER]);

#262              }

#263              integer2bytestream(code->mStates->mCodeChunk, nooffset, mGlobalScope->mStateCount);

#264              mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, code->mStates, NULL, stacksize, entry,

#265   entrycount, NULL);

#266  

#267              // now, put it all together and spit it out

#268              // we need

#269              FILE* bcfp = LLFile::fopen(mBytecodeDest, "wb");         /*Flawfinder: ignore*/

#270             

#271              code->build(fp, bcfp);

#272              fclose(bcfp);

#273                                         

#274              delete code;

#275          }

#276          break;

 

输出 CIL 的汇编代码。

#277      case LSCP_EMIT_CIL_ASSEMBLY:

#278  

#279          // Output dependencies.

#280          fprintf(fp, ".assembly extern mscorlib {.ver 1:0:5000:0}/n");

#281          fprintf(fp, ".assembly extern LScriptLibrary {.ver 0:0:0:0}/n");

#282  

#283          // Output assembly name.

#284          fprintf(fp, ".assembly 'lsl' {.ver 0:0:0:0}/n");

#285  

#286          // Output class header.

#287          fprintf(fp, ".class public auto ansi beforefieldinit LSL extends [mscorlib]System.Object/n");

#288          fprintf(fp, "{/n");

#289  

#290          // Output globals as members.

#291          if(NULL != mGlobals)

#292          {

#293              print_cil_globals(fp, mGlobals);

#294          }

#295  

#296          // Output "runtime". Only needed to allow stand alone execution. Not needed when compiling to DLL and using embedded runtime.

#297          fprintf(fp, ".method public static   hidebysig default void Main ()   cil managed/n");

#298          fprintf(fp, "{/n");

#299          fprintf(fp, ".entrypoint/n");

#300          fprintf(fp, ".maxstack 2/n");

#301          fprintf(fp, ".locals init (class LSL V_0)/n");

#302          fprintf(fp, "newobj instance void class LSL::.ctor()/n");

#303          fprintf(fp, "stloc.0/n");

#304          fprintf(fp, "ldloc.0/n");

#305          fprintf(fp, "callvirt instance void class LSL::defaultstate_entry()/n");

#306          fprintf(fp, "ret/n");

#307          fprintf(fp, "}/n");

#308  

#309          // Output ctor header.

#310          fprintf(fp, ".method public hidebysig   specialname   rtspecialname instance default void .ctor ()   cil managed/n");

#311          fprintf(fp, "{/n");

#312          fprintf(fp, ".maxstack 500/n");

#313  

#314          // Initialise globals as members in ctor.

#315          if (mGlobals)

#316          {

#317              fdotabs(fp, tabs, tabsize);

#318              mGlobals->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount,

#319   NULL);

#320              fprintf(fp, "/n");

#321          }

#322  

#323          // Output ctor footer.

#324          fprintf(fp, "ldarg.0/n");

#325          fprintf(fp, "call instance void valuetype [mscorlib]System.Object::.ctor()/n");

#326          fprintf(fp, "ret/n");

#327          fprintf(fp, "}/n");

#328  

#329          // Output functions as methods.

#330          if (mGlobalFunctions)

#331          {

#332              fdotabs(fp, tabs, tabsize);

#333              mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry,

#334   entrycount, NULL);

#335              fprintf(fp, "/n");

#336          }

#337  

#338          // Output states as name mangled methods.

#339          fdotabs(fp, tabs, tabsize);

#340          mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);

#341          fprintf(fp, "/n");

#342  

#343          // Output class footer.

#344          fprintf(fp, "}/n");

#345  

#346          break;

 

下面进行缺省的处理。

#347      default:

#348          if (mGlobals)

#349              mGlobals->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount,

#350   NULL);

#351          if (mGlobalFunctions)

#352              mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry,

#353   entrycount, NULL);

#354          mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);

#355          break;

#356      }

#357   }

#358  

 

通过上面的代码,看到对脚本代码完整的分析过程,其实它是依照下面的状态来进行不同的阶段处理的,如下:

#001   typedef enum e_lscript_compile_pass

#002   {

 

非法编译状态。

#003      LSCP_INVALID,

 

输出合适的说明文字

#004      LSCP_PRETTY_PRINT,

 

进行代码化减和优化。

#005      LSCP_PRUNE,

 

对脚本代码进行全局的作用域检查。

#006      LSCP_SCOPE_PASS1,

 

对脚本代码进行跳转等作用域检查。

#007      LSCP_SCOPE_PASS2,

 

对脚本代码进行类型检查。

#008      LSCP_TYPE,

 

对脚本代码进行需要的资源分配。

#009      LSCP_RESOURCE,

 

对脚本代码进行汇编输出处理。

#010      LSCP_EMIT_ASSEMBLY,

 

对脚本代码进行字节码编译输出。

#011      LSCP_EMIT_BYTE_CODE,

 

对脚本代码进行事件处理计数。

#012      LSCP_DETERMINE_HANDLERS,

 

输出 LIB 数据。

#013      LSCP_LIST_BUILD_SIMPLE,

 

对于栈进行处理。

#014      LSCP_TO_STACK,

 

函数声明参数处理。

#015      LSCP_BUILD_FUNCTION_ARGS,

 

对脚本代码进行 CIL 汇编输出。

#016      LSCP_EMIT_CIL_ASSEMBLY,

 

脚本处理结束状态。

#017      LSCP_EOF

#018   } LSCRIPTCompilePass;

 

因此一个脚本代码需要经过上面 13 种的组合分析,才会真正地处理完脚本的编译,这是一个非常复杂漫长的过程。

 

第二人生的源码分析(112)脚本的综合分析(2)


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论