wsasm.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:27k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  *
  3.  * wsasm.c
  4.  *
  5.  * Author: Markku Rossi <mtr@iki.fi>
  6.  *
  7.  * Copyright (c) 1999-2000 WAPIT OY LTD.
  8.  *  All rights reserved.
  9.  *
  10.  * Byte-code assembler.
  11.  *
  12.  */
  13. #include "wsint.h"
  14. #include "wsasm.h"
  15. #include "wsstdlib.h"
  16. /********************* Macros to fetch items from BC operands ***********/
  17. #define WS_OPNAME(op) (operands[(op)].name)
  18. #define WS_OPSIZE(op) (operands[(op)].size)
  19. /********************* Byte-code operands *******************************/
  20. static struct
  21. {
  22.     char *name;
  23.     int size;
  24. } operands[256] = {
  25. #include "wsopcodes.h"
  26. };
  27. /********************* Symbolic assembler instructions ******************/
  28. /* General helpers. */
  29. void ws_asm_link(WsCompiler *compiler, WsAsmIns *ins)
  30. {
  31.     if (compiler->asm_tail) {
  32.         compiler->asm_tail->next = ins;
  33.         ins->prev = compiler->asm_tail;
  34.         compiler->asm_tail = ins;
  35.     } else
  36.         compiler->asm_tail = compiler->asm_head = ins;
  37. }
  38. void ws_asm_print(WsCompiler *compiler)
  39. {
  40.     WsAsmIns *ins;
  41.     for (ins = compiler->asm_head; ins; ins = ins->next) {
  42.         if (ins->type > 0xff) {
  43.             /* A symbolic operand. */
  44.             switch (ins->type) {
  45.             case WS_ASM_P_LABEL:
  46.                 ws_fprintf(WS_STDOUT, ".L%d:tttt/* refcount=%d */n",
  47.                            ins->ws_label_idx, ins->ws_label_refcount);
  48.                 break;
  49.             case WS_ASM_P_JUMP:
  50.                 ws_fprintf(WS_STDOUT, "tjump*ttL%dn",
  51.                            ins->ws_label->ws_label_idx);
  52.                 break;
  53.             case WS_ASM_P_TJUMP:
  54.                 ws_fprintf(WS_STDOUT, "ttjump*ttL%dn",
  55.                            ins->ws_label->ws_label_idx);
  56.                 break;
  57.             case WS_ASM_P_CALL:
  58.                 ws_fprintf(WS_STDOUT, "tcall*tt%sn",
  59.                            compiler->functions[ins->ws_findex].name);
  60.                 break;
  61.             case WS_ASM_P_CALL_LIB:
  62.                 {
  63.                     const char *lib;
  64.                     const char *func;
  65.                     ws_stdlib_function_name(ins->ws_lindex,
  66.                                             ins->ws_findex,
  67.                                             &lib, &func);
  68.                     ws_fprintf(WS_STDOUT, "tcall_lib*t%s.%sn",
  69.                                lib ? lib : "???",
  70.                                func ? func : "???");
  71.                 }
  72.                 break;
  73.             case WS_ASM_P_CALL_URL:
  74.                 ws_fprintf(WS_STDOUT, "tcall_url*t%u %u %un",
  75.                            ins->ws_lindex, ins->ws_findex, ins->ws_args);
  76.                 break;
  77.             case WS_ASM_P_LOAD_VAR:
  78.                 ws_fprintf(WS_STDOUT, "tload_var*t%un", ins->ws_vindex);
  79.                 break;
  80.             case WS_ASM_P_STORE_VAR:
  81.                 ws_fprintf(WS_STDOUT, "tstore_var*t%un", ins->ws_vindex);
  82.                 break;
  83.             case WS_ASM_P_INCR_VAR:
  84.                 ws_fprintf(WS_STDOUT, "tincr_var*t%un", ins->ws_vindex);
  85.                 break;
  86.             case WS_ASM_P_LOAD_CONST:
  87.                 ws_fprintf(WS_STDOUT, "tload_const*t%un", ins->ws_cindex);
  88.                 break;
  89.             }
  90.         } else {
  91.             WsUInt8 op = WS_ASM_OP(ins->type);
  92.             if (operands[op].name) {
  93.                 /* Operands add_asg and sub_asg are special. */
  94.                 if (op == WS_ASM_ADD_ASG || op == WS_ASM_SUB_ASG)
  95.                     ws_fprintf(WS_STDOUT, "t%stt%un", operands[ins->type].name,
  96.                                ins->ws_vindex);
  97.                 else
  98.                     ws_fprintf(WS_STDOUT, "t%sn", operands[ins->type].name);
  99.             } else
  100.                 ws_fatal("ws_asm_print(): unknown operand 0x%x", op);
  101.         }
  102.     }
  103. }
  104. void ws_asm_dasm(WsCompilerPtr compiler, const unsigned char *code, size_t len)
  105. {
  106.     size_t i = 0;
  107.     while (i < len) {
  108.         WsUInt8 byt = code[i];
  109.         WsUInt8 op;
  110.         WsUInt8 arg;
  111.         WsUInt8 i8, j8, k8;
  112.         WsUInt16 i16, j16;
  113.         op = WS_ASM_OP(byt);
  114.         arg = WS_ASM_ARG(byt);
  115.         ws_fprintf(WS_STDOUT, "%4x:t%-16s", i, WS_OPNAME(op));
  116.         switch (op) {
  117.             /* The `short jumps'. */
  118.         case WS_ASM_JUMP_FW_S:
  119.         case WS_ASM_TJUMP_FW_S:
  120.             ws_fprintf(WS_STDOUT, "%xn", i + WS_OPSIZE(op) + arg);
  121.             break;
  122.         case WS_ASM_JUMP_BW_S:
  123.             ws_fprintf(WS_STDOUT, "%xn", i - arg);
  124.             break;
  125.             /* Jumps with WsUInt8 argument. */
  126.         case WS_ASM_JUMP_FW:
  127.         case WS_ASM_TJUMP_FW:
  128.             WS_GET_UINT8(code + i + 1, i8);
  129.             ws_fprintf(WS_STDOUT, "%xn", i + WS_OPSIZE(op) + i8);
  130.             break;
  131.         case WS_ASM_JUMP_BW:
  132.         case WS_ASM_TJUMP_BW:
  133.             WS_GET_UINT8(code + i + 1, i8);
  134.             ws_fprintf(WS_STDOUT, "%xn", i - i8);
  135.             break;
  136.             /* Jumps with wide argument. */
  137.         case WS_ASM_JUMP_FW_W:
  138.         case WS_ASM_TJUMP_FW_W:
  139.             WS_GET_UINT16(code + i + 1, i16);
  140.             ws_fprintf(WS_STDOUT, "%xn", i + WS_OPSIZE(op) + i16);
  141.             break;
  142.         case WS_ASM_JUMP_BW_W:
  143.         case WS_ASM_TJUMP_BW_W:
  144.             WS_GET_UINT16(code + i + 1, i16);
  145.             ws_fprintf(WS_STDOUT, "%xn", i - i16);
  146.             break;
  147.             /* The `short' opcodes. */
  148.         case WS_ASM_LOAD_VAR_S:
  149.         case WS_ASM_STORE_VAR_S:
  150.         case WS_ASM_INCR_VAR_S:
  151.             ws_fprintf(WS_STDOUT, "%dn", arg);
  152.             break;
  153.             /* Local script function calls. */
  154.         case WS_ASM_CALL_S:
  155.             ws_fprintf(WS_STDOUT, "%dn", arg);
  156.             break;
  157.         case WS_ASM_CALL:
  158.             WS_GET_UINT8(code + i + 1, i8);
  159.             ws_fprintf(WS_STDOUT, "%dn", i8);
  160.             break;
  161.             /* Library calls. */
  162.         case WS_ASM_CALL_LIB_S:
  163.         case WS_ASM_CALL_LIB:
  164.         case WS_ASM_CALL_LIB_W:
  165.             {
  166.                 WsUInt8 findex;
  167.                 WsUInt16 lindex;
  168.                 char lnamebuf[64];
  169.                 char fnamebuf[64];
  170.                 const char *lname;
  171.                 const char *fname;
  172.                 if (op == WS_ASM_CALL_LIB_S) {
  173.                     WS_GET_UINT8(code + i + 1, lindex);
  174.                     findex = arg;
  175.                 } else if (op == WS_ASM_CALL_LIB) {
  176.                     WS_GET_UINT8(code + i + 1, findex);
  177.                     WS_GET_UINT8(code + i + 2, lindex);
  178.                 } else {
  179.                     WS_GET_UINT8(code + i + 1, findex);
  180.                     WS_GET_UINT16(code + i + 2, lindex);
  181.                 }
  182.                 if (!ws_stdlib_function_name(lindex, findex, &lname, &fname)) {
  183.                     snprintf(lnamebuf, sizeof(lnamebuf), "%d", lindex);
  184.                     snprintf(fnamebuf, sizeof(lnamebuf), "%d", findex);
  185.                     lname = lnamebuf;
  186.                     fname = fnamebuf;
  187.                 }
  188.                 ws_fprintf(WS_STDOUT, "%s.%sn", lname, fname);
  189.             }
  190.             break;
  191.             /* URL calls. */
  192.         case WS_ASM_CALL_URL:
  193.             WS_GET_UINT8(code + i + 1, i8);
  194.             WS_GET_UINT8(code + i + 2, j8);
  195.             WS_GET_UINT8(code + i + 3, k8);
  196.             ws_fprintf(WS_STDOUT, "%d.%d %dn", i8, j8, k8);
  197.             break;
  198.         case WS_ASM_CALL_URL_W:
  199.             WS_GET_UINT16(code + i + 1, i16);
  200.             WS_GET_UINT16(code + i + 3, j16);
  201.             WS_GET_UINT8(code + i + 5, i8);
  202.             ws_fprintf(WS_STDOUT, "%d.%d %dn", i16, j16, i8);
  203.             break;
  204.             /* Constant access. */
  205.         case WS_ASM_LOAD_CONST_S:
  206.         case WS_ASM_LOAD_CONST:
  207.         case WS_ASM_LOAD_CONST_W:
  208.             if (op == WS_ASM_LOAD_CONST_S)
  209.                 i16 = arg;
  210.             else if (op == WS_ASM_LOAD_CONST) {
  211.                 WS_GET_UINT8(code + i + 1, i8);
  212.                 i16 = i8;
  213.             } else
  214.                 WS_GET_UINT16(code + i + 1, i16);
  215.             ws_fprintf(WS_STDOUT, "%dn", i16);
  216.             break;
  217.             /* Operands with WsUInt8 argument. */
  218.         case WS_ASM_LOAD_VAR:
  219.         case WS_ASM_STORE_VAR:
  220.         case WS_ASM_INCR_VAR:
  221.         case WS_ASM_DECR_VAR:
  222.         case WS_ASM_ADD_ASG:
  223.         case WS_ASM_SUB_ASG:
  224.             WS_GET_UINT8(code + i + 1, i8);
  225.             ws_fprintf(WS_STDOUT, "%dn", i8);
  226.             break;
  227.             /* The trivial cases. */
  228.         default:
  229.             ws_fprintf(WS_STDOUT, "n");
  230.             break;
  231.         }
  232.         i += WS_OPSIZE(op);
  233.     }
  234. }
  235. void
  236. ws_asm_linearize(WsCompiler *compiler)
  237. {
  238.     WsAsmIns *ins;
  239.     WsBool process_again = WS_TRUE;
  240.     /* Calculate all offsets and select real assembler instructions for
  241.        our internal pseudo instructions.  This is continued as long as
  242.        the code changes. */
  243.     while (process_again) {
  244.         WsUInt32 offset = 1;
  245.         process_again = WS_FALSE;
  246.         for (ins = compiler->asm_head; ins; ins = ins->next) {
  247.             ins->offset = offset;
  248.             switch (ins->type) {
  249.             case WS_ASM_JUMP_FW_S:
  250.                 ins->ws_offset = (ins->ws_label->offset
  251.                                   - (offset + WS_OPSIZE(ins->type)));
  252.                 break;
  253.             case WS_ASM_JUMP_FW:
  254.                 ins->ws_offset = (ins->ws_label->offset
  255.                                   - (offset + WS_OPSIZE(ins->type)));
  256.                 if (ins->ws_offset <= 31) {
  257.                     ins->type = WS_ASM_JUMP_FW_S;
  258.                     process_again = WS_TRUE;
  259.                 }
  260.                 break;
  261.             case WS_ASM_JUMP_FW_W:
  262.                 ins->ws_offset = (ins->ws_label->offset
  263.                                   - (offset + WS_OPSIZE(ins->type)));
  264.                 if (ins->ws_offset <= 31) {
  265.                     ins->type = WS_ASM_JUMP_FW_S;
  266.                     process_again = WS_TRUE;
  267.                 } else if (ins->ws_offset <= 255) {
  268.                     ins->type = WS_ASM_JUMP_FW;
  269.                     process_again = WS_TRUE;
  270.                 }
  271.                 break;
  272.             case WS_ASM_JUMP_BW_S:
  273.                 ins->ws_offset = offset - ins->ws_label->offset;
  274.                 break;
  275.             case WS_ASM_JUMP_BW:
  276.                 ins->ws_offset = offset - ins->ws_label->offset;
  277.                 if (ins->ws_offset <= 31) {
  278.                     ins->type = WS_ASM_JUMP_BW_S;
  279.                     process_again = WS_TRUE;
  280.                 }
  281.                 break;
  282.             case WS_ASM_JUMP_BW_W:
  283.                 ins->ws_offset = offset - ins->ws_label->offset;
  284.                 if (ins->ws_offset <= 31) {
  285.                     ins->type = WS_ASM_JUMP_BW_S;
  286.                     process_again = WS_TRUE;
  287.                 } else if (ins->ws_offset <= 255) {
  288.                     ins->type = WS_ASM_JUMP_BW;
  289.                     process_again = WS_TRUE;
  290.                 }
  291.                 break;
  292.             case WS_ASM_TJUMP_FW_S:
  293.                 ins->ws_offset = (ins->ws_label->offset
  294.                                   - (offset + WS_OPSIZE(ins->type)));
  295.                 break;
  296.             case WS_ASM_TJUMP_FW:
  297.                 ins->ws_offset = (ins->ws_label->offset
  298.                                   - (offset + WS_OPSIZE(ins->type)));
  299.                 if (ins->ws_offset <= 31) {
  300.                     ins->type = WS_ASM_TJUMP_FW_S;
  301.                     process_again = WS_TRUE;
  302.                 }
  303.                 break;
  304.             case WS_ASM_TJUMP_FW_W:
  305.                 ins->ws_offset = (ins->ws_label->offset
  306.                                   - (offset + WS_OPSIZE(ins->type)));
  307.                 if (ins->ws_offset <= 31) {
  308.                     ins->type = WS_ASM_TJUMP_FW_S;
  309.                     process_again = WS_TRUE;
  310.                 } else if (ins->ws_offset <= 255) {
  311.                     ins->type = WS_ASM_TJUMP_FW;
  312.                     process_again = WS_TRUE;
  313.                 }
  314.                 break;
  315.             case WS_ASM_TJUMP_BW:
  316.                  ins->ws_offset = offset - ins->ws_label->offset;
  317.                  break;
  318.             case WS_ASM_TJUMP_BW_W:
  319.                 ins->ws_offset = offset - ins->ws_label->offset;
  320.                 if (ins->ws_offset <= 255) {
  321.                     ins->type = WS_ASM_TJUMP_BW;
  322.                     process_again = WS_TRUE;
  323.                 }
  324.                 break;
  325.                 /*
  326.                  * The pseudo instructions.
  327.                  */
  328.             case WS_ASM_P_LABEL:
  329.                 /* Nothing here. */
  330.                 break;
  331.             case WS_ASM_P_JUMP:
  332.                 if (ins->ws_label->offset == 0) {
  333.                     /* A forward jump.  Let's assume the widest form. */
  334.                     ins->type = WS_ASM_JUMP_FW_W;
  335.                 } else {
  336.                     ins->ws_offset = offset - ins->ws_label->offset;
  337.                     /* Jump backwards. */
  338.                     if (ins->ws_offset <= 31) {
  339.                         ins->type = WS_ASM_JUMP_BW_S;
  340.                     } else if (ins->ws_offset <= 255) {
  341.                         ins->type = WS_ASM_JUMP_BW;
  342.                     } else {
  343.                         ins->type = WS_ASM_JUMP_BW_W;
  344.                     }
  345.                 }
  346.                 break;
  347.             case WS_ASM_P_TJUMP:
  348.                 if (ins->ws_label->offset == 0) {
  349.                     /* A forward jump.  Let's assume the widest form. */
  350.                     ins->type = WS_ASM_TJUMP_FW_W;
  351.                     process_again = WS_TRUE;
  352.                 } else {
  353.                     ins->ws_offset = offset - ins->ws_label->offset;
  354.                     /* Jump backwards. */
  355.                     if (ins->ws_offset <= 255) {
  356.                         ins->type = WS_ASM_TJUMP_BW;
  357.                     } else {
  358.                         ins->type = WS_ASM_TJUMP_BW_W;
  359.                     }
  360.                 }
  361.                 break;
  362.             case WS_ASM_P_CALL:
  363.                 if (ins->ws_findex <= 7) {
  364.                     /* The most compact form. */
  365.                     ins->type = WS_ASM_CALL_S;
  366.                 } else {
  367.                     /* The wider form. */
  368.                     ins->type = WS_ASM_CALL;
  369.                 }
  370.                 break;
  371.             case WS_ASM_P_CALL_LIB:
  372.                 if (ins->ws_findex <= 7 && ins->ws_lindex <= 255) {
  373.                     /* The most compact form. */
  374.                     ins->type = WS_ASM_CALL_LIB_S;
  375.                 } else if (ins->ws_findex <= 255 && ins->ws_lindex <= 255) {
  376.                     /* The quite compact form. */
  377.                     ins->type = WS_ASM_CALL_LIB;
  378.                 } else {
  379.                     /* The most liberal form. */
  380.                     ins->type = WS_ASM_CALL_LIB_W;
  381.                 }
  382.                 break;
  383.             case WS_ASM_P_CALL_URL:
  384.                 if (ins->ws_findex <= 255 && ins->ws_lindex <= 255)
  385.                     /* The compact form. */
  386.                     ins->type = WS_ASM_CALL_URL;
  387.                 else
  388.                     ins->type = WS_ASM_CALL_URL_W;
  389.                 break;
  390.             case WS_ASM_P_LOAD_VAR:
  391.                 if (ins->ws_vindex <= 31)
  392.                     /* The compact form. */
  393.                     ins->type = WS_ASM_LOAD_VAR_S;
  394.                 else
  395.                     ins->type = WS_ASM_LOAD_VAR;
  396.                 break;
  397.             case WS_ASM_P_STORE_VAR:
  398.                 if (ins->ws_vindex <= 15)
  399.                     ins->type = WS_ASM_STORE_VAR_S;
  400.                 else
  401.                     ins->type = WS_ASM_STORE_VAR;
  402.                 break;
  403.             case WS_ASM_P_INCR_VAR:
  404.                 if (ins->ws_vindex <= 7)
  405.                     ins->type = WS_ASM_INCR_VAR_S;
  406.                 else
  407.                     ins->type = WS_ASM_INCR_VAR;
  408.                 break;
  409.             case WS_ASM_P_LOAD_CONST:
  410.                 if (ins->ws_cindex <= 15)
  411.                     ins->type = WS_ASM_LOAD_CONST_S;
  412.                 else if (ins->ws_cindex <= 255)
  413.                     ins->type = WS_ASM_LOAD_CONST;
  414.                 else
  415.                     ins->type = WS_ASM_LOAD_CONST_W;
  416.                 break;
  417.             }
  418.             gw_assert(ins->type == WS_ASM_P_LABEL || ins->type < 0x100);
  419.             if (ins->type != WS_ASM_P_LABEL) {
  420.                 gw_assert(operands[ins->type].name != NULL);
  421.                 offset += operands[ins->type].size;
  422.             }
  423.         }
  424.     }
  425.     /* Ok, ready to linearize the byte-code. */
  426.     for (ins = compiler->asm_head; ins; ins = ins->next) {
  427.         if (ins->type == WS_ASM_P_LABEL)
  428.             continue;
  429.         gw_assert(ins->type <= 0xff);
  430.         switch (ins->type) {
  431.         case WS_ASM_JUMP_FW_S:
  432.         case WS_ASM_JUMP_BW_S:
  433.         case WS_ASM_TJUMP_FW_S:
  434.             if (!ws_encode_buffer(&compiler->byte_code,
  435.                                   WS_ENC_BYTE,
  436.                                   WS_ASM_GLUE(ins->type, ins->ws_offset),
  437.                                   WS_ENC_END))
  438.                 goto error;
  439.             break;
  440.         case WS_ASM_JUMP_FW:
  441.         case WS_ASM_JUMP_BW:
  442.         case WS_ASM_TJUMP_FW:
  443.         case WS_ASM_TJUMP_BW:
  444.             if (!ws_encode_buffer(&compiler->byte_code,
  445.                                   WS_ENC_BYTE, ins->type,
  446.                                   WS_ENC_UINT8, (WsUInt8) ins->ws_offset,
  447.                                   WS_ENC_END))
  448.                 goto error;
  449.             break;
  450.         case WS_ASM_JUMP_FW_W:
  451.         case WS_ASM_JUMP_BW_W:
  452.         case WS_ASM_TJUMP_FW_W:
  453.         case WS_ASM_TJUMP_BW_W:
  454.             if (!ws_encode_buffer(&compiler->byte_code,
  455.                                   WS_ENC_BYTE, ins->type,
  456.                                   WS_ENC_UINT16, (WsUInt16) ins->ws_offset,
  457.                                   WS_ENC_END))
  458.                 goto error;
  459.             break;
  460.         case WS_ASM_CALL_S:
  461.             if (!ws_encode_buffer(&compiler->byte_code,
  462.                                   WS_ENC_BYTE,
  463.                                   WS_ASM_GLUE(ins->type, ins->ws_findex),
  464.                                   WS_ENC_END))
  465.                 goto error;
  466.             break;
  467.         case WS_ASM_CALL:
  468.             if (!ws_encode_buffer(&compiler->byte_code,
  469.                                   WS_ENC_BYTE, (WsByte) ins->type,
  470.                                   WS_ENC_UINT8, (WsUInt8) ins->ws_findex,
  471.                                   WS_ENC_END))
  472.                 goto error;
  473.             break;
  474.         case WS_ASM_CALL_LIB_S:
  475.             if (!ws_encode_buffer(&compiler->byte_code,
  476.                                   WS_ENC_BYTE,
  477.                                   WS_ASM_GLUE(ins->type, ins->ws_findex),
  478.                                   WS_ENC_UINT8, (WsUInt8) ins->ws_lindex,
  479.                                   WS_ENC_END))
  480.                 goto error;
  481.             break;
  482.         case WS_ASM_CALL_LIB:
  483.             if (!ws_encode_buffer(&compiler->byte_code,
  484.                                   WS_ENC_BYTE, (WsByte) ins->type,
  485.                                   WS_ENC_UINT8, (WsUInt8) ins->ws_findex,
  486.                                   WS_ENC_UINT8, (WsUInt8) ins->ws_lindex,
  487.                                   WS_ENC_END))
  488.                 goto error;
  489.             break;
  490.         case WS_ASM_CALL_LIB_W:
  491.             if (!ws_encode_buffer(&compiler->byte_code,
  492.                                   WS_ENC_BYTE, (WsByte) ins->type,
  493.                                   WS_ENC_UINT8, (WsUInt8) ins->ws_findex,
  494.                                   WS_ENC_UINT16, (WsUInt16) ins->ws_lindex,
  495.                                   WS_ENC_END))
  496.                 goto error;
  497.             break;
  498.         case WS_ASM_CALL_URL:
  499.             if (!ws_encode_buffer(&compiler->byte_code,
  500.                                   WS_ENC_BYTE, (WsByte) ins->type,
  501.                                   WS_ENC_UINT8, (WsUInt8) ins->ws_lindex,
  502.                                   WS_ENC_UINT8, (WsUInt8) ins->ws_findex,
  503.                                   WS_ENC_UINT8, (WsUInt8) ins->ws_args,
  504.                                   WS_ENC_END))
  505.                 goto error;
  506.             break;
  507.         case WS_ASM_CALL_URL_W:
  508.             if (!ws_encode_buffer(&compiler->byte_code,
  509.                                   WS_ENC_BYTE, (WsByte) ins->type,
  510.                                   WS_ENC_UINT16, (WsUInt16) ins->ws_lindex,
  511.                                   WS_ENC_UINT16, (WsUInt16) ins->ws_findex,
  512.                                   WS_ENC_UINT8, (WsUInt8) ins->ws_args,
  513.                                   WS_ENC_END))
  514.                 goto error;
  515.             break;
  516.         case WS_ASM_LOAD_VAR_S:
  517.         case WS_ASM_STORE_VAR_S:
  518.             if (!ws_encode_buffer(&compiler->byte_code,
  519.                                   WS_ENC_BYTE,
  520.                                   WS_ASM_GLUE(ins->type, ins->ws_vindex),
  521.                                   WS_ENC_END))
  522.                 goto error;
  523.             break;
  524.         case WS_ASM_LOAD_VAR:
  525.         case WS_ASM_STORE_VAR:
  526.             if (!ws_encode_buffer(&compiler->byte_code,
  527.                                   WS_ENC_BYTE, (WsByte) ins->type,
  528.                                   WS_ENC_UINT8, (WsUInt8) ins->ws_vindex,
  529.                                   WS_ENC_END))
  530.                 goto error;
  531.             break;
  532.         case WS_ASM_INCR_VAR_S:
  533.             if (!ws_encode_buffer(&compiler->byte_code,
  534.                                   WS_ENC_BYTE,
  535.                                   WS_ASM_GLUE(ins->type, ins->ws_vindex),
  536.                                   WS_ENC_END))
  537.                 goto error;
  538.             break;
  539.         case WS_ASM_INCR_VAR:
  540.         case WS_ASM_DECR_VAR:
  541.             if (!ws_encode_buffer(&compiler->byte_code,
  542.                                   WS_ENC_BYTE, (WsByte) ins->type,
  543.                                   WS_ENC_UINT8, (WsUInt8) ins->ws_vindex,
  544.                                   WS_ENC_END))
  545.                 goto error;
  546.             break;
  547.         case WS_ASM_LOAD_CONST_S:
  548.             if (!ws_encode_buffer(&compiler->byte_code,
  549.                                   WS_ENC_BYTE,
  550.                                   WS_ASM_GLUE(ins->type, ins->ws_cindex),
  551.                                   WS_ENC_END))
  552.                 goto error;
  553.             break;
  554.         case WS_ASM_LOAD_CONST:
  555.             if (!ws_encode_buffer(&compiler->byte_code,
  556.                                   WS_ENC_BYTE, (WsByte) ins->type,
  557.                                   WS_ENC_UINT8, (WsUInt8) ins->ws_cindex,
  558.                                   WS_ENC_END))
  559.                 goto error;
  560.             break;
  561.         case WS_ASM_LOAD_CONST_W:
  562.             if (!ws_encode_buffer(&compiler->byte_code,
  563.                                   WS_ENC_BYTE, (WsByte) ins->type,
  564.                                   WS_ENC_UINT16, (WsUInt16) ins->ws_cindex,
  565.                                   WS_ENC_END))
  566.                 goto error;
  567.             break;
  568.         case WS_ASM_ADD_ASG:
  569.         case WS_ASM_SUB_ASG:
  570.             if (!ws_encode_buffer(&compiler->byte_code,
  571.                                   WS_ENC_BYTE, (WsByte) ins->type,
  572.                                   WS_ENC_UINT8, (WsUInt8) ins->ws_vindex,
  573.                                   WS_ENC_END))
  574.                 goto error;
  575.             break;
  576.         case WS_ASM_CONST_0:
  577.         case WS_ASM_CONST_1:
  578.         case WS_ASM_CONST_M1:
  579.         case WS_ASM_CONST_ES:
  580.         case WS_ASM_CONST_INVALID:
  581.         case WS_ASM_CONST_TRUE:
  582.         case WS_ASM_CONST_FALSE:
  583.         case WS_ASM_INCR:
  584.         case WS_ASM_DECR:
  585.         case WS_ASM_UMINUS:
  586.         case WS_ASM_ADD:
  587.         case WS_ASM_SUB:
  588.         case WS_ASM_MUL:
  589.         case WS_ASM_DIV:
  590.         case WS_ASM_IDIV:
  591.         case WS_ASM_REM:
  592.         case WS_ASM_B_AND:
  593.         case WS_ASM_B_OR:
  594.         case WS_ASM_B_XOR:
  595.         case WS_ASM_B_NOT:
  596.         case WS_ASM_B_LSHIFT:
  597.         case WS_ASM_B_RSSHIFT:
  598.         case WS_ASM_B_RSZSHIFT:
  599.         case WS_ASM_EQ:
  600.         case WS_ASM_LE:
  601.         case WS_ASM_LT:
  602.         case WS_ASM_GE:
  603.         case WS_ASM_GT:
  604.         case WS_ASM_NE:
  605.         case WS_ASM_NOT:
  606.         case WS_ASM_SCAND:
  607.         case WS_ASM_SCOR:
  608.         case WS_ASM_TOBOOL:
  609.         case WS_ASM_POP:
  610.         case WS_ASM_TYPEOF:
  611.         case WS_ASM_ISVALID:
  612.         case WS_ASM_RETURN:
  613.         case WS_ASM_RETURN_ES:
  614.         case WS_ASM_DEBUG:
  615.             if (!ws_encode_buffer(&compiler->byte_code,
  616.                                   WS_ENC_BYTE, (WsByte) ins->type,
  617.                                   WS_ENC_END))
  618.                 goto error;
  619.             break;
  620.         default:
  621.             ws_fatal("ws_asm_linearize(): unknown instruction 0x%02x",
  622.                      ins->type);
  623.             break;
  624.         }
  625.     }
  626.     /*
  627.      * Avoid generating 0-length functions, because not all clients
  628.      * handle them correctly.
  629.      */
  630.     if (ws_buffer_len(&compiler->byte_code) == 0) {
  631. if (!ws_encode_buffer(&compiler->byte_code,
  632.           WS_ENC_BYTE, (WsByte) WS_ASM_RETURN_ES,
  633.       WS_ENC_END))
  634.     goto error;
  635.     }
  636.     return;
  637.     /*
  638.      * Error handling.
  639.      */
  640. error:
  641.     ws_error_memory(compiler);
  642.     return;
  643. }
  644. /* Contructors for assembler instructions. */
  645. static WsAsmIns *asm_alloc(WsCompiler *compiler, WsUInt16 type, WsUInt32 line)
  646. {
  647.     WsAsmIns *ins = ws_f_calloc(compiler->pool_asm, 1, sizeof(*ins));
  648.     if (ins == NULL)
  649.         ws_error_memory(compiler);
  650.     else {
  651.         ins->type = type;
  652.         ins->line = line;
  653.     }
  654.     return ins;
  655. }
  656. WsAsmIns *ws_asm_label(WsCompiler *compiler, WsUInt32 line)
  657. {
  658.     WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_LABEL, line);
  659.     if (ins)
  660.         ins->ws_label_idx = compiler->next_label++;
  661.     return ins;
  662. }
  663. WsAsmIns *ws_asm_branch(WsCompiler *compiler, WsUInt32 line, WsUInt16 inst,
  664.                         WsAsmIns *label)
  665. {
  666.     WsAsmIns *ins = asm_alloc(compiler, inst, line);
  667.     if (ins) {
  668.         ins->ws_label = label;
  669.         label->ws_label_refcount++;
  670.     }
  671.     return ins;
  672. }
  673. WsAsmIns *ws_asm_call(WsCompiler *compiler, WsUInt32 line, WsUInt8 findex)
  674. {
  675.     WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_CALL, line);
  676.     if (ins)
  677.         ins->ws_findex = findex;
  678.     return ins;
  679. }
  680. WsAsmIns *ws_asm_call_lib(WsCompiler *compiler, WsUInt32 line, WsUInt8 findex,
  681.                 WsUInt16 lindex)
  682. {
  683.     WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_CALL_LIB, line);
  684.     if (ins) {
  685.         ins->ws_findex = findex;
  686.         ins->ws_lindex = lindex;
  687.     }
  688.     return ins;
  689. }
  690. WsAsmIns *ws_asm_call_url(WsCompiler *compiler, WsUInt32 line, WsUInt16 findex,
  691.                           WsUInt16 urlindex, WsUInt8 args)
  692. {
  693.     WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_CALL_URL, line);
  694.     if (ins) {
  695.         ins->ws_findex = findex;
  696.         ins->ws_lindex = urlindex;
  697.         ins->ws_args = args;
  698.     }
  699.     return ins;
  700. }
  701. WsAsmIns *ws_asm_variable(WsCompiler *compiler, WsUInt32 line, WsUInt16 inst,
  702.                           WsUInt8 vindex)
  703. {
  704.     WsAsmIns *ins = asm_alloc(compiler, inst, line);
  705.     if (ins)
  706.         ins->ws_vindex = vindex;
  707.     return ins;
  708. }
  709. WsAsmIns *ws_asm_load_const(WsCompiler *compiler, WsUInt32 line,
  710.                             WsUInt16 cindex)
  711. {
  712.     WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_LOAD_CONST, line);
  713.     if (ins)
  714.         ins->ws_cindex = cindex;
  715.     return ins;
  716. }
  717. WsAsmIns *ws_asm_ins(WsCompiler *compiler, WsUInt32 line, WsUInt8 opcode)
  718. {
  719.     return asm_alloc(compiler, opcode, line);
  720. }