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; }
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; }