Пример #1
0
WsBool ws_bc_encode(WsBc *bc, unsigned char **data_return,
                    size_t *data_len_return)
{
    WsBuffer buffer;
    WsUInt32 ui;
    unsigned char data[64];
    unsigned char *p, *mb;
    size_t len;

    ws_buffer_init(&buffer);

    /* Append space for the header.  We do not know yet the size of the
       resulting byte-code. */
    if (!ws_buffer_append_space(&buffer, NULL, WS_BC_MAX_HEADER_LEN))
        goto error;


    /* Constants. */

    if (!ws_encode_buffer(&buffer,
                          WS_ENC_MB_UINT16, bc->num_constants,
                          WS_ENC_MB_UINT16, (WsUInt16) bc->string_encoding,
                          WS_ENC_END))
        goto error;

    for (ui = 0 ; ui < bc->num_constants; ui++) {
        switch (bc->constants[ui].type) {
        case WS_BC_CONST_TYPE_INT:
            if (WS_INT8_MIN <= bc->constants[ui].u.v_int
                    && bc->constants[ui].u.v_int <= WS_INT8_MAX) {
                if (!ws_encode_buffer(&buffer,
                                      WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_INT8,
                                      WS_ENC_INT8,
                                      (WsInt8) bc->constants[ui].u.v_int,
                                      WS_ENC_END))
                    goto error;
            } else if (WS_INT16_MIN <= bc->constants[ui].u.v_int
                       && bc->constants[ui].u.v_int <= WS_INT16_MAX) {
                if (!ws_encode_buffer(&buffer,
                                      WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_INT16,
                                      WS_ENC_INT16,
                                      (WsInt16) bc->constants[ui].u.v_int,
                                      WS_ENC_END))
                    goto error;
            } else {
                if (!ws_encode_buffer(&buffer,
                                      WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_INT32,
                                      WS_ENC_INT32, bc->constants[ui].u.v_int,
                                      WS_ENC_END))
                    goto error;
            }
            break;

        case WS_BC_CONST_TYPE_FLOAT32:
        case WS_BC_CONST_TYPE_FLOAT32_NAN:
        case WS_BC_CONST_TYPE_FLOAT32_POSITIVE_INF:
        case WS_BC_CONST_TYPE_FLOAT32_NEGATIVE_INF:
            switch (bc->constants[ui].type) {
            case WS_BC_CONST_TYPE_FLOAT32:
                ws_ieee754_encode_single(bc->constants[ui].u.v_float, data);
                p = data;
                break;

            case WS_BC_CONST_TYPE_FLOAT32_NAN:
                p = ws_ieee754_nan;
                break;

            case WS_BC_CONST_TYPE_FLOAT32_POSITIVE_INF:
                p = ws_ieee754_positive_inf;
                break;

            case WS_BC_CONST_TYPE_FLOAT32_NEGATIVE_INF:
                p = ws_ieee754_negative_inf;
                break;

            default:
                ws_fatal("ws_bc_encode(): internal inconsistency");
                /* NOTREACHED */
                p = NULL; 		/* Initialized to keep compiler quiet. */
                break;
            }

            if (!ws_encode_buffer(&buffer,
                                  WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_FLOAT32,
                                  WS_ENC_DATA, p, 4,
                                  WS_ENC_END))
                goto error;
            break;

            break;

        case WS_BC_CONST_TYPE_UTF8_STRING:
            /* Encode the strings as requested. */
            switch (bc->string_encoding) {
            case WS_BC_STRING_ENC_ISO_8859_1:
            {
                WsUtf8String *string = ws_utf8_alloc();
                unsigned char *latin1;
                size_t latin1_len;
                WsBool success;

                if (string == NULL)
                    goto error;

                /* Create an UTF-8 string. */
                if (!ws_utf8_set_data(string,
                                      bc->constants[ui].u.v_string.data,
                                      bc->constants[ui].u.v_string.len)) {
                    ws_utf8_free(string);
                    goto error;
                }

                /* Convert it to latin1. */
                latin1 = ws_utf8_to_latin1(string, '?', &latin1_len);

                /* We'r done with the UTF-8 string. */
                ws_utf8_free(string);

                if (latin1 == NULL)
                    goto error;

                /* Encode it. */
                success = ws_encode_buffer(
                              &buffer,
                              WS_ENC_UINT8,
                              (WsUInt8) WS_BC_CONST_EXT_ENC_STRING,

                              WS_ENC_MB_UINT32, (WsUInt32) latin1_len,
                              WS_ENC_DATA, latin1, latin1_len,

                              WS_ENC_END);
                ws_utf8_free_data(latin1);

                if (!success)
                    goto error;
            }
            break;

            case WS_BC_STRING_ENC_UTF8:
                if (!ws_encode_buffer(
                            &buffer,
                            WS_ENC_UINT8,
                            (WsUInt8) WS_BC_CONST_UTF8_STRING,

                            WS_ENC_MB_UINT32,
                            (WsUInt32) bc->constants[ui].u.v_string.len,

                            WS_ENC_DATA,
                            bc->constants[ui].u.v_string.data,
                            bc->constants[ui].u.v_string.len,

                            WS_ENC_END))
                    goto error;
                break;
            }
            break;

        case WS_BC_CONST_TYPE_EMPTY_STRING:
            if (!ws_encode_buffer(&buffer,
                                  WS_ENC_UINT8,
                                  (WsUInt8) WS_BC_CONST_EMPTY_STRING,
                                  WS_ENC_END))
                goto error;
            break;
        }
    }


    /* Pragmas. */

    if (!ws_encode_buffer(&buffer,
                          WS_ENC_MB_UINT16, bc->num_pragmas,
                          WS_ENC_END))
        goto error;

    for (ui = 0; ui < bc->num_pragmas; ui++) {
        switch (bc->pragmas[ui].type) {
        case WS_BC_PRAGMA_TYPE_ACCESS_DOMAIN:
            if (!ws_encode_buffer(&buffer,
                                  WS_ENC_UINT8,
                                  (WsUInt8) WS_BC_PRAGMA_ACCESS_DOMAIN,

                                  WS_ENC_MB_UINT16, bc->pragmas[ui].index_1,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_BC_PRAGMA_TYPE_ACCESS_PATH:
            if (!ws_encode_buffer(&buffer,
                                  WS_ENC_UINT8,
                                  (WsUInt8) WS_BC_PRAGMA_ACCESS_PATH,
                                  WS_ENC_MB_UINT16, bc->pragmas[ui].index_1,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_BC_PRAGMA_TYPE_USER_AGENT_PROPERTY:
            if (!ws_encode_buffer(&buffer,
                                  WS_ENC_UINT8,
                                  (WsUInt8) WS_BC_PRAGMA_USER_AGENT_PROPERTY,
                                  WS_ENC_MB_UINT16, bc->pragmas[ui].index_1,
                                  WS_ENC_MB_UINT16, bc->pragmas[ui].index_2,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_BC_PRAGMA_TYPE_USER_AGENT_PROPERTY_AND_SCHEME:
            if (!ws_encode_buffer(
                        &buffer,
                        WS_ENC_UINT8,
                        (WsUInt8) WS_BC_PRAGMA_USER_AGENT_PROPERTY_AND_SCHEME,
                        WS_ENC_MB_UINT16, bc->pragmas[ui].index_1,
                        WS_ENC_MB_UINT16, bc->pragmas[ui].index_2,
                        WS_ENC_MB_UINT16, bc->pragmas[ui].index_3,
                        WS_ENC_END))
                goto error;
            break;
        }
    }


    /* Function pool. */

    if (!ws_encode_buffer(&buffer,
                          WS_ENC_UINT8, bc->num_functions,
                          WS_ENC_END))
        goto error;

    /* Function names. */

    if (!ws_encode_buffer(&buffer,
                          WS_ENC_UINT8, bc->num_function_names,
                          WS_ENC_END))
        goto error;

    for (ui = 0; ui < bc->num_function_names; ui++) {
        size_t name_len = strlen(bc->function_names[ui].name);

        if (!ws_encode_buffer(&buffer,
                              WS_ENC_UINT8, bc->function_names[ui].index,
                              WS_ENC_UINT8, (WsUInt8) name_len,
                              WS_ENC_DATA, bc->function_names[ui].name, name_len,
                              WS_ENC_END))
            goto error;
    }

    /* Functions. */

    for (ui = 0; ui < bc->num_functions; ui++) {
        if (!ws_encode_buffer(&buffer,
                              WS_ENC_UINT8, bc->functions[ui].num_arguments,
                              WS_ENC_UINT8, bc->functions[ui].num_locals,
                              WS_ENC_MB_UINT32, bc->functions[ui].code_size,
                              WS_ENC_DATA, bc->functions[ui].code,
                              (size_t) bc->functions[ui].code_size,
                              WS_ENC_END))
            goto error;
    }


    /* Fix the byte-code header. */

    p = ws_buffer_ptr(&buffer);

    /* Encode the size of the byte-code excluding the byte-code header. */
    mb = ws_encode_mb_uint32(ws_buffer_len(&buffer) - WS_BC_MAX_HEADER_LEN,
                             data, &len);
    memcpy(p + WS_BC_MAX_HEADER_LEN - len, mb, len);

    /* Set the byte-code file version information. */
    WS_PUT_UINT8(p + WS_BC_MAX_HEADER_LEN - len - 1, WS_BC_VERSION);

    /* Calculate the beginning of the bc-array and its size. */
    *data_return = p + WS_BC_MAX_HEADER_LEN - len - 1;
    *data_len_return = ws_buffer_len(&buffer) - WS_BC_MAX_HEADER_LEN + len + 1;

    /* All done. */
    return WS_TRUE;


    /*
     * Error handling.
     */

error:

    ws_buffer_uninit(&buffer);
    *data_return = NULL;
    *data_len_return = 0;

    return WS_FALSE;
}
Пример #2
0
void
ws_asm_linearize(WsCompiler *compiler)
{
    WsAsmIns *ins;
    WsBool process_again = WS_TRUE;

    /* Calculate all offsets and select real assembler instructions for
       our internal pseudo instructions.  This is continued as long as
       the code changes. */
    while (process_again) {
        WsUInt32 offset = 1;

        process_again = WS_FALSE;

        for (ins = compiler->asm_head; ins; ins = ins->next) {
            ins->offset = offset;

            switch (ins->type) {
            case WS_ASM_JUMP_FW_S:
                ins->ws_offset = (ins->ws_label->offset
                                  - (offset + WS_OPSIZE(ins->type)));
                break;

            case WS_ASM_JUMP_FW:
                ins->ws_offset = (ins->ws_label->offset
                                  - (offset + WS_OPSIZE(ins->type)));

                if (ins->ws_offset <= 31) {
                    ins->type = WS_ASM_JUMP_FW_S;
                    process_again = WS_TRUE;
                }
                break;

            case WS_ASM_JUMP_FW_W:
                ins->ws_offset = (ins->ws_label->offset
                                  - (offset + WS_OPSIZE(ins->type)));

                if (ins->ws_offset <= 31) {
                    ins->type = WS_ASM_JUMP_FW_S;
                    process_again = WS_TRUE;
                } else if (ins->ws_offset <= 255) {
                    ins->type = WS_ASM_JUMP_FW;
                    process_again = WS_TRUE;
                }
                break;

            case WS_ASM_JUMP_BW_S:
                ins->ws_offset = offset - ins->ws_label->offset;
                break;

            case WS_ASM_JUMP_BW:
                ins->ws_offset = offset - ins->ws_label->offset;

                if (ins->ws_offset <= 31) {
                    ins->type = WS_ASM_JUMP_BW_S;
                    process_again = WS_TRUE;
                }
                break;

            case WS_ASM_JUMP_BW_W:
                ins->ws_offset = offset - ins->ws_label->offset;

                if (ins->ws_offset <= 31) {
                    ins->type = WS_ASM_JUMP_BW_S;
                    process_again = WS_TRUE;
                } else if (ins->ws_offset <= 255) {
                    ins->type = WS_ASM_JUMP_BW;
                    process_again = WS_TRUE;
                }
                break;

            case WS_ASM_TJUMP_FW_S:
                ins->ws_offset = (ins->ws_label->offset
                                  - (offset + WS_OPSIZE(ins->type)));
                break;

            case WS_ASM_TJUMP_FW:
                ins->ws_offset = (ins->ws_label->offset
                                  - (offset + WS_OPSIZE(ins->type)));

                if (ins->ws_offset <= 31) {
                    ins->type = WS_ASM_TJUMP_FW_S;
                    process_again = WS_TRUE;
                }
                break;

            case WS_ASM_TJUMP_FW_W:
                ins->ws_offset = (ins->ws_label->offset
                                  - (offset + WS_OPSIZE(ins->type)));

                if (ins->ws_offset <= 31) {
                    ins->type = WS_ASM_TJUMP_FW_S;
                    process_again = WS_TRUE;
                } else if (ins->ws_offset <= 255) {
                    ins->type = WS_ASM_TJUMP_FW;
                    process_again = WS_TRUE;
                }
                break;

            case WS_ASM_TJUMP_BW:
                 ins->ws_offset = offset - ins->ws_label->offset;
                 break;

            case WS_ASM_TJUMP_BW_W:
                ins->ws_offset = offset - ins->ws_label->offset;

                if (ins->ws_offset <= 255) {
                    ins->type = WS_ASM_TJUMP_BW;
                    process_again = WS_TRUE;
                }
                break;

                /*
                 * The pseudo instructions.
                 */

            case WS_ASM_P_LABEL:
                /* Nothing here. */
                break;

            case WS_ASM_P_JUMP:
                if (ins->ws_label->offset == 0) {
                    /* A forward jump.  Let's assume the widest form. */
                    ins->type = WS_ASM_JUMP_FW_W;
                } else {
                    ins->ws_offset = offset - ins->ws_label->offset;

                    /* Jump backwards. */
                    if (ins->ws_offset <= 31) {
                        ins->type = WS_ASM_JUMP_BW_S;
                    } else if (ins->ws_offset <= 255) {
                        ins->type = WS_ASM_JUMP_BW;
                    } else {
                        ins->type = WS_ASM_JUMP_BW_W;
                    }
                }
                break;

            case WS_ASM_P_TJUMP:
                if (ins->ws_label->offset == 0) {
                    /* A forward jump.  Let's assume the widest form. */
                    ins->type = WS_ASM_TJUMP_FW_W;
                    process_again = WS_TRUE;
                } else {
                    ins->ws_offset = offset - ins->ws_label->offset;

                    /* Jump backwards. */
                    if (ins->ws_offset <= 255) {
                        ins->type = WS_ASM_TJUMP_BW;
                    } else {
                        ins->type = WS_ASM_TJUMP_BW_W;
                    }
                }
                break;

            case WS_ASM_P_CALL:
                if (ins->ws_findex <= 7) {
                    /* The most compact form. */
                    ins->type = WS_ASM_CALL_S;
                } else {
                    /* The wider form. */
                    ins->type = WS_ASM_CALL;
                }
                break;

            case WS_ASM_P_CALL_LIB:
                if (ins->ws_findex <= 7 && ins->ws_lindex <= 255) {
                    /* The most compact form. */
                    ins->type = WS_ASM_CALL_LIB_S;
                } else if (ins->ws_findex <= 255 && ins->ws_lindex <= 255) {
                    /* The quite compact form. */
                    ins->type = WS_ASM_CALL_LIB;
                } else {
                    /* The most liberal form. */
                    ins->type = WS_ASM_CALL_LIB_W;
                }
                break;

            case WS_ASM_P_CALL_URL:
                if (ins->ws_findex <= 255 && ins->ws_lindex <= 255)
                    /* The compact form. */
                    ins->type = WS_ASM_CALL_URL;
                else
                    ins->type = WS_ASM_CALL_URL_W;
                break;

            case WS_ASM_P_LOAD_VAR:
                if (ins->ws_vindex <= 31)
                    /* The compact form. */
                    ins->type = WS_ASM_LOAD_VAR_S;
                else
                    ins->type = WS_ASM_LOAD_VAR;
                break;

            case WS_ASM_P_STORE_VAR:
                if (ins->ws_vindex <= 15)
                    ins->type = WS_ASM_STORE_VAR_S;
                else
                    ins->type = WS_ASM_STORE_VAR;
                break;

            case WS_ASM_P_INCR_VAR:
                if (ins->ws_vindex <= 7)
                    ins->type = WS_ASM_INCR_VAR_S;
                else
                    ins->type = WS_ASM_INCR_VAR;
                break;

            case WS_ASM_P_LOAD_CONST:
                if (ins->ws_cindex <= 15)
                    ins->type = WS_ASM_LOAD_CONST_S;
                else if (ins->ws_cindex <= 255)
                    ins->type = WS_ASM_LOAD_CONST;
                else
                    ins->type = WS_ASM_LOAD_CONST_W;
                break;
            }

            gw_assert(ins->type == WS_ASM_P_LABEL || ins->type < 0x100);

            if (ins->type != WS_ASM_P_LABEL) {
                gw_assert(operands[ins->type].name != NULL);
                offset += operands[ins->type].size;
            }
        }
    }

    /* Ok, ready to linearize the byte-code. */
    for (ins = compiler->asm_head; ins; ins = ins->next) {
        if (ins->type == WS_ASM_P_LABEL)
            continue;

        gw_assert(ins->type <= 0xff);

        switch (ins->type) {
        case WS_ASM_JUMP_FW_S:
        case WS_ASM_JUMP_BW_S:
        case WS_ASM_TJUMP_FW_S:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE,
                                  WS_ASM_GLUE(ins->type, ins->ws_offset),
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_JUMP_FW:
        case WS_ASM_JUMP_BW:
        case WS_ASM_TJUMP_FW:
        case WS_ASM_TJUMP_BW:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, ins->type,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_offset,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_JUMP_FW_W:
        case WS_ASM_JUMP_BW_W:
        case WS_ASM_TJUMP_FW_W:
        case WS_ASM_TJUMP_BW_W:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, ins->type,
                                  WS_ENC_UINT16, (WsUInt16) ins->ws_offset,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_CALL_S:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE,
                                  WS_ASM_GLUE(ins->type, ins->ws_findex),
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_CALL:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_findex,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_CALL_LIB_S:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE,
                                  WS_ASM_GLUE(ins->type, ins->ws_findex),
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_lindex,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_CALL_LIB:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_findex,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_lindex,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_CALL_LIB_W:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_findex,
                                  WS_ENC_UINT16, (WsUInt16) ins->ws_lindex,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_CALL_URL:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_lindex,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_findex,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_args,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_CALL_URL_W:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT16, (WsUInt16) ins->ws_lindex,
                                  WS_ENC_UINT16, (WsUInt16) ins->ws_findex,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_args,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_LOAD_VAR_S:
        case WS_ASM_STORE_VAR_S:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE,
                                  WS_ASM_GLUE(ins->type, ins->ws_vindex),
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_LOAD_VAR:
        case WS_ASM_STORE_VAR:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_vindex,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_INCR_VAR_S:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE,
                                  WS_ASM_GLUE(ins->type, ins->ws_vindex),
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_INCR_VAR:
        case WS_ASM_DECR_VAR:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_vindex,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_LOAD_CONST_S:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE,
                                  WS_ASM_GLUE(ins->type, ins->ws_cindex),
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_LOAD_CONST:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_cindex,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_LOAD_CONST_W:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT16, (WsUInt16) ins->ws_cindex,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_ADD_ASG:
        case WS_ASM_SUB_ASG:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_UINT8, (WsUInt8) ins->ws_vindex,
                                  WS_ENC_END))
                goto error;
            break;

        case WS_ASM_CONST_0:
        case WS_ASM_CONST_1:
        case WS_ASM_CONST_M1:
        case WS_ASM_CONST_ES:
        case WS_ASM_CONST_INVALID:
        case WS_ASM_CONST_TRUE:
        case WS_ASM_CONST_FALSE:
        case WS_ASM_INCR:
        case WS_ASM_DECR:
        case WS_ASM_UMINUS:
        case WS_ASM_ADD:
        case WS_ASM_SUB:
        case WS_ASM_MUL:
        case WS_ASM_DIV:
        case WS_ASM_IDIV:
        case WS_ASM_REM:
        case WS_ASM_B_AND:
        case WS_ASM_B_OR:
        case WS_ASM_B_XOR:
        case WS_ASM_B_NOT:
        case WS_ASM_B_LSHIFT:
        case WS_ASM_B_RSSHIFT:
        case WS_ASM_B_RSZSHIFT:
        case WS_ASM_EQ:
        case WS_ASM_LE:
        case WS_ASM_LT:
        case WS_ASM_GE:
        case WS_ASM_GT:
        case WS_ASM_NE:
        case WS_ASM_NOT:
        case WS_ASM_SCAND:
        case WS_ASM_SCOR:
        case WS_ASM_TOBOOL:
        case WS_ASM_POP:
        case WS_ASM_TYPEOF:
        case WS_ASM_ISVALID:
        case WS_ASM_RETURN:
        case WS_ASM_RETURN_ES:
        case WS_ASM_DEBUG:
            if (!ws_encode_buffer(&compiler->byte_code,
                                  WS_ENC_BYTE, (WsByte) ins->type,
                                  WS_ENC_END))
                goto error;
            break;

        default:
            ws_fatal("ws_asm_linearize(): unknown instruction 0x%02x",
                     ins->type);
            break;
        }
    }

    /*
     * Avoid generating 0-length functions, because not all clients
     * handle them correctly.
     */
    if (ws_buffer_len(&compiler->byte_code) == 0) {
	if (!ws_encode_buffer(&compiler->byte_code,
	   		      WS_ENC_BYTE, (WsByte) WS_ASM_RETURN_ES,
			      WS_ENC_END))
	    goto error;
    }

    return;

    /*
     * Error handling.
     */

error:

    ws_error_memory(compiler);
    return;
}