Example #1
0
WsBc *ws_bc_decode(const unsigned char *data, size_t data_len)
{
    WsBc *bc = ws_bc_alloc(WS_BC_STRING_ENC_ISO_8859_1);
    WsByte b;
    WsUInt32 ui32;
    WsUInt16 ui16, j;
    WsUInt16 ui16b;
    WsUInt8 ui8, num_functions, k, l;
    WsInt8 i8;
    WsInt16 i16;
    WsInt32 i32;
    WsIeee754Result ieee754;
    unsigned char *ucp;
    size_t decoded;

    /* Decode the byte-code header. */
    decoded = ws_decode_buffer(data, data_len,
                               WS_ENC_BYTE, &b,
                               WS_ENC_MB_UINT32, &ui32,
                               WS_ENC_END);

    if (!decoded
            || b != WS_BC_VERSION
            || ui32 != data_len - decoded)
        /* This is not a valid (or supported) byte-code header. */
        goto error;

    WS_UPDATE_DATA;

    /* Constant pool. */

    decoded = ws_decode_buffer(data, data_len,
                               WS_ENC_MB_UINT16, &ui16,
                               WS_ENC_MB_UINT16, &ui16b,
                               WS_ENC_END);
    if (!decoded)
        goto error;

    bc->string_encoding = ui16b;

    bc->constants = ws_calloc(ui16, sizeof(WsBcConstant));
    if (bc->constants == NULL)
        goto error;
    bc->num_constants = ui16;

    WS_UPDATE_DATA;

    for (j = 0; j < bc->num_constants; j++) {
        WsBcConstant *c = &bc->constants[j];

        decoded = ws_decode_buffer(data, data_len,
                                   WS_ENC_UINT8, &ui8,
                                   WS_ENC_END);
        if (decoded != 1)
            goto error;

        WS_UPDATE_DATA;

        switch (ui8) {
        case WS_BC_CONST_INT8:
            decoded = ws_decode_buffer(data, data_len,
                                       WS_ENC_INT8, &i8,
                                       WS_ENC_END);
            if (decoded != 1)
                goto error;

            WS_UPDATE_DATA;

            c->type = WS_BC_CONST_TYPE_INT;
            c->u.v_int = i8;
            break;

        case WS_BC_CONST_INT16:
            decoded = ws_decode_buffer(data, data_len,
                                       WS_ENC_INT16, &i16,
                                       WS_ENC_END);
            if (decoded != 2)
                goto error;

            WS_UPDATE_DATA;

            c->type = WS_BC_CONST_TYPE_INT;
            c->u.v_int = i16;
            break;

        case WS_BC_CONST_INT32:
            decoded = ws_decode_buffer(data, data_len,
                                       WS_ENC_INT32, &i32,
                                       WS_ENC_END);
            if (decoded != 4)
                goto error;

            WS_UPDATE_DATA;

            c->type = WS_BC_CONST_TYPE_INT;
            c->u.v_int = i32;
            break;

        case WS_BC_CONST_FLOAT32:
            decoded = ws_decode_buffer(data, data_len,
                                       WS_ENC_DATA, &ucp, (size_t) 4,
                                       WS_ENC_END);
            if (decoded != 4)
                goto error;

            WS_UPDATE_DATA;

            ieee754 = ws_ieee754_decode_single(ucp, &c->u.v_float);

            switch (ieee754) {
            case WS_IEEE754_OK:
                c->type = WS_BC_CONST_TYPE_FLOAT32;
                break;

            case WS_IEEE754_NAN:
                c->type = WS_BC_CONST_TYPE_FLOAT32_NAN;
                break;

            case WS_IEEE754_POSITIVE_INF:
                c->type = WS_BC_CONST_TYPE_FLOAT32_POSITIVE_INF;
                break;

            case WS_IEEE754_NEGATIVE_INF:
                c->type = WS_BC_CONST_TYPE_FLOAT32_NEGATIVE_INF;
                break;
            }

            break;

        case WS_BC_CONST_UTF8_STRING:
            decoded = ws_decode_buffer(data, data_len,
                                       WS_ENC_MB_UINT32, &ui32,
                                       WS_ENC_END);
            if (decoded == 0)
                goto error;

            WS_UPDATE_DATA;

            c->type = WS_BC_CONST_TYPE_UTF8_STRING;
            c->u.v_string.len = ui32;

            decoded = ws_decode_buffer(data, data_len,
                                       WS_ENC_DATA, &ucp, c->u.v_string.len,
                                       WS_ENC_END);
            if (decoded != ui32)
                goto error;

            WS_UPDATE_DATA;

            c->u.v_string.data = ws_memdup(ucp, ui32);
            if (c->u.v_string.data == NULL)
                goto error;

            /* Check the validity of the data. */
            if (!ws_utf8_verify(c->u.v_string.data, c->u.v_string.len,
                                &c->u.v_string.num_chars))
                goto error;
            break;

        case WS_BC_CONST_EMPTY_STRING:
            c->type = WS_BC_CONST_TYPE_EMPTY_STRING;
            break;

        case WS_BC_CONST_EXT_ENC_STRING:
            ws_fatal("external character encoding not implemented yet");
            break;

        default:
            /* Reserved. */
            goto error;
            break;
        }
    }

    /* Pragma pool. */

    decoded = ws_decode_buffer(data, data_len,
                               WS_ENC_MB_UINT16, &ui16,
                               WS_ENC_END);
    if (!decoded)
        goto error;

    bc->pragmas = ws_calloc(ui16, sizeof(WsBcPragma));
    if (bc->pragmas == NULL)
        goto error;
    bc->num_pragmas = ui16;

    WS_UPDATE_DATA;

    for (j = 0; j < bc->num_pragmas; j++) {
        WsBcPragma *p = &bc->pragmas[j];

        decoded = ws_decode_buffer(data, data_len,
                                   WS_ENC_UINT8, &ui8,
                                   WS_ENC_END);
        if (decoded != 1)
            goto error;

        WS_UPDATE_DATA;

        p->type = ui8;

        switch (ui8) {
        case WS_BC_PRAGMA_ACCESS_DOMAIN:
            decoded = ws_decode_buffer(data, data_len,
                                       WS_ENC_MB_UINT16, &p->index_1,
                                       WS_ENC_END);
            if (!decoded)
                goto error;

            WS_CHECK_STRING(p->index_1);
            break;

        case WS_BC_PRAGMA_ACCESS_PATH:
            decoded = ws_decode_buffer(data, data_len,
                                       WS_ENC_MB_UINT16, &p->index_1,
                                       WS_ENC_END);
            if (!decoded)
                goto error;

            WS_CHECK_STRING(p->index_1);
            break;

        case WS_BC_PRAGMA_USER_AGENT_PROPERTY:
            decoded = ws_decode_buffer(data, data_len,
                                       WS_ENC_MB_UINT16, &p->index_1,
                                       WS_ENC_MB_UINT16, &p->index_2,
                                       WS_ENC_END);
            if (!decoded)
                goto error;

            WS_CHECK_STRING(p->index_1);
            WS_CHECK_STRING(p->index_2);
            break;

        case WS_BC_PRAGMA_USER_AGENT_PROPERTY_AND_SCHEME:
            decoded = ws_decode_buffer(data, data_len,
                                       WS_ENC_MB_UINT16, &p->index_1,
                                       WS_ENC_MB_UINT16, &p->index_2,
                                       WS_ENC_MB_UINT16, &p->index_3,
                                       WS_ENC_END);
            if (!decoded)
                goto error;

            WS_CHECK_STRING(p->index_1);
            WS_CHECK_STRING(p->index_2);
            WS_CHECK_STRING(p->index_3);
            break;

        default:
            goto error;
            break;
        }

        WS_UPDATE_DATA;
    }

    /* Function pool. */

    decoded = ws_decode_buffer(data, data_len,
                               WS_ENC_UINT8, &num_functions,
                               WS_ENC_END);
    if (decoded != 1)
        goto error;

    WS_UPDATE_DATA;

    /* Function names. */

    decoded = ws_decode_buffer(data, data_len,
                               WS_ENC_UINT8, &ui8,
                               WS_ENC_END);
    if (decoded != 1)
        goto error;

    WS_UPDATE_DATA;

    if (ui8) {
        /* We have function names. */
        bc->function_names = ws_calloc(ui8, sizeof(WsBcFunctionName));
        if (bc->function_names == NULL)
            goto error;
        bc->num_function_names = ui8;

        for (k = 0; k < bc->num_function_names; k++) {
            WsBcFunctionName *n = &bc->function_names[k];

            decoded = ws_decode_buffer(data, data_len,
                                       WS_ENC_UINT8, &n->index,
                                       WS_ENC_UINT8, &ui8,
                                       WS_ENC_END);
            if (decoded != 2)
                goto error;

            WS_UPDATE_DATA;

            decoded = ws_decode_buffer(data, data_len,
                                       WS_ENC_DATA, &ucp, (size_t) ui8,
                                       WS_ENC_END);
            if (decoded != ui8)
                goto error;

            WS_UPDATE_DATA;

            n->name = ws_memdup(ucp, ui8);
            if (n->name == NULL)
                goto error;

            /* Check the validity of the name. */

            if (!ws_utf8_verify((unsigned char *) n->name, ui8, NULL))
                goto error;

            /* Just check that the data contains only valid characters. */
            for (l = 0; l < ui8; l++) {
                unsigned int ch = (unsigned char) n->name[l];

                if (('a' <= ch && ch <= 'z')
                        || ('A' <= ch && ch <= 'Z')
                        || ch == '_'
                        || (l > 0 && ('0' <= ch && ch <= '9')))
                    /* Ok. */
                    continue;

                /* Invalid character in the function name. */
                goto error;
            }

            /* Is the index valid? */
            if (n->index >= num_functions)
                goto error;
        }
    }

    /* Functions. */

    if (num_functions) {
        /* We have functions. */
        bc->functions = ws_calloc(num_functions, sizeof(WsBcFunction));
        if (bc->functions == NULL)
            goto error;
        bc->num_functions = num_functions;

        for (k = 0; k < bc->num_functions; k++) {
            WsBcFunction *f = &bc->functions[k];

            decoded = ws_decode_buffer(data, data_len,
                                       WS_ENC_UINT8, &f->num_arguments,
                                       WS_ENC_UINT8, &f->num_locals,
                                       WS_ENC_MB_UINT32, &f->code_size,
                                       WS_ENC_END);
            if (!decoded)
                goto error;

            WS_UPDATE_DATA;

            decoded = ws_decode_buffer(data, data_len,
                                       WS_ENC_DATA, &ucp, f->code_size,
                                       WS_ENC_END);
            if (decoded != f->code_size)
                goto error;

            WS_UPDATE_DATA;

            if (f->code_size) {
                /* It is not an empty function. */
                f->code = ws_memdup(ucp, f->code_size);
                if (f->code == NULL)
                    goto error;
            }
        }
    }

    /* Did we process it all? */
    if (data_len != 0)
        goto error;

    /* All done. */
    return bc;

    /*
     * Error handling.
     */

error:

    ws_bc_free(bc);

    return NULL;
}
Example #2
0
File: ws.c Project: markjeee/kannel
static WsResult compile_stream(WsCompilerPtr compiler, const char *input_name,
                               WsStream *input, unsigned char **output_return,
                               size_t *output_len_return)
{
    WsResult result = WS_OK;
    WsUInt32 i;
    WsListItem *li;
    WsUInt8 findex;
    WsUInt8 num_locals;
    WsBcStringEncoding string_encoding = WS_BC_STRING_ENC_UTF8;

    /* Initialize the compiler context. */

    compiler->linenum = 1;
    compiler->input_name = input_name;

    compiler->num_errors = 0;
    compiler->num_warnings = 0;
    compiler->num_extern_functions = 0;
    compiler->num_local_functions = 0;
    compiler->errors = 0;
    compiler->last_syntax_error_line = 0;

    /* Allocate fast-malloc pool for the syntax tree. */

    compiler->pool_stree = ws_f_create(1024 * 1024);
    if (compiler->pool_stree == NULL) {
        result = WS_ERROR_OUT_OF_MEMORY;
        goto out;
    }

    /* Allocate hash tables. */

    compiler->pragma_use_hash = ws_pragma_use_hash_create();
    if (compiler->pragma_use_hash == NULL) {
        result = WS_ERROR_OUT_OF_MEMORY;
        goto out;
    }

    compiler->functions_hash = ws_function_hash_create();
    if (compiler->functions_hash == NULL) {
        result = WS_ERROR_OUT_OF_MEMORY;
        goto out;
    }

    /* Allocate a byte-code module. */

    if (compiler->params.use_latin1_strings)
        string_encoding = WS_BC_STRING_ENC_ISO_8859_1;

    compiler->bc = ws_bc_alloc(string_encoding);
    if (compiler->bc == NULL) {
        result = WS_ERROR_OUT_OF_MEMORY;
        goto out;
    }

    /* Save the input stream. */
    compiler->input = input;

    /* Parse the input. */
#if WS_DEBUG
    global_compiler = compiler;
#endif /* WS_DEBUG */

    ws_yy_parse(compiler);

    /* Free all lexer's active not freed blocks.  If we have any blocks
       on the used list, our compilation was not successful. */
    {
        size_t j;

        for (j = 0; j < compiler->lexer_active_list_size; j++)
            ws_free(compiler->lexer_active_list[j]);
        ws_free(compiler->lexer_active_list);

        compiler->lexer_active_list = NULL;
    }

    WS_CHECK_COMPILE_ERROR();

    /* Sort functions if allowed and it helps. */
    if (!compiler->params.no_opt_sort_bc_functions
        && compiler->num_functions > 7) {
        WsUInt32 i;

        ws_info(compiler, "optimize: sorting functions");

        /* Fetch the usage counts from the functions hash. */
        for (i = 0; i < compiler->num_functions; i++) {
            WsFunctionHash *fh = ws_function_hash(compiler,
                                                  compiler->functions[i].name);
            compiler->functions[i].usage_count = fh->usage_count;
        }

        /* Sort functions.  */
        qsort(compiler->functions, compiler->num_functions,
              sizeof(compiler->functions[0]), sort_functions_cmp);

        /* Patch the function indexes. */
        for (i = 0; i < compiler->num_functions; i++) {
            WsFunctionHash *fh = ws_function_hash(compiler,
                                                  compiler->functions[i].name);
            compiler->functions[i].findex = i;
            fh->findex = i;
        }
    }

    /* Linearize functions */
    for (i = 0; i < compiler->num_functions; i++) {
        WsFunction *func = &compiler->functions[i];

        ws_info(compiler, "linearizing function `%s'...", func->name);

        compiler->pool_asm = ws_f_create(100 * 1024);
        if (compiler->pool_asm == NULL) {
            result = WS_ERROR_OUT_OF_MEMORY;
            goto out;
        }

        compiler->next_label = 0;
        compiler->asm_head = compiler->asm_tail = NULL;

        /* Create variables namespace. */
        compiler->next_vindex = 0;
        compiler->variables_hash = ws_variable_hash_create();
        if (compiler->variables_hash == NULL) {
            result = WS_ERROR_OUT_OF_MEMORY;
            goto out;
        }

        /* Define the formal arguments to the namespace. */
        for (li = func->params->head; li; li = li->next) {
            WsFormalParm *parm = li->data;

            ws_variable_define(compiler, parm->line, WS_FALSE, parm->name);
        }

        WS_CHECK_COMPILE_ERROR();

        /* Linearize it. */
        for (li = func->block->head; li; li = li->next)
            ws_stmt_linearize(compiler, li->data);

        WS_CHECK_COMPILE_ERROR();

        /* Optimize symbolic assembler.  This function does nothing if
           no optimizations were requested. */
        ws_asm_optimize(compiler);

        /* Print the resulting symbolic assembler if requested. */
        if (compiler->params.print_symbolic_assembler)
            ws_asm_print(compiler);

        WS_CHECK_COMPILE_ERROR();

        /* Generate byte-code */

        ws_buffer_init(&compiler->byte_code);
        ws_asm_linearize(compiler);

        WS_CHECK_COMPILE_ERROR();

        /* Disassemble the output if requested. */
        if (compiler->params.print_assembler)
            ws_asm_dasm(compiler, ws_buffer_ptr(&compiler->byte_code),
                        ws_buffer_len(&compiler->byte_code));

        /* Calculate the number of local variables */
        num_locals = compiler->next_vindex - func->params->num_items;

        /* Add the function to the byte-code module. */
        if (!ws_bc_add_function(compiler->bc, &findex,
                                func->externp ? func->name : NULL,
                                func->params->num_items,
                                num_locals,
                                ws_buffer_len(&compiler->byte_code),
                                ws_buffer_ptr(&compiler->byte_code))) {
            result = WS_ERROR_OUT_OF_MEMORY;
            goto out;
        }

        /* Cleanup and prepare for the next function. */

        ws_buffer_uninit(&compiler->byte_code);

        ws_hash_destroy(compiler->variables_hash);
        compiler->variables_hash = NULL;

        ws_f_destroy(compiler->pool_asm);
        compiler->pool_asm = NULL;
    }

    /* Linearize the byte-code structure. */
    if (!ws_bc_encode(compiler->bc, output_return, output_len_return))
        result = WS_ERROR_OUT_OF_MEMORY;

out:

    /* Cleanup. */

    ws_f_destroy(compiler->pool_stree);
    compiler->pool_stree = NULL;

    ws_hash_destroy(compiler->pragma_use_hash);
    compiler->pragma_use_hash = NULL;

    /* Free functions. */
    for (i = 0; i < compiler->num_functions; i++)
        ws_free(compiler->functions[i].name);
    ws_free(compiler->functions);

    ws_hash_destroy(compiler->functions_hash);
    compiler->functions_hash = NULL;

    ws_bc_free(compiler->bc);
    compiler->bc = NULL;

    compiler->input = NULL;

    ws_f_destroy(compiler->pool_asm);
    compiler->pool_asm = NULL;

    ws_hash_destroy(compiler->variables_hash);
    compiler->variables_hash = NULL;

    ws_buffer_uninit(&compiler->byte_code);

    /* All done. */
    return result;
}