unsigned char *ws_utf8_to_latin1(const WsUtf8String *string, unsigned char unknown_char, size_t *len_return) { unsigned char *cstr; size_t i; size_t pos = 0; if (string == NULL) return NULL; cstr = ws_malloc(string->num_chars + 1); if (cstr == NULL) return NULL; for (i = 0; i < string->num_chars; i++) { unsigned long ch; if (!ws_utf8_get_char(string, &ch, &pos)) ws_fatal("ws_utf8_to_latin1_cstr(): internal inconsistency"); if (ch > 0xff) cstr[i] = unknown_char; else cstr[i] = (unsigned char) ch; } cstr[i] = '\0'; if (len_return) *len_return = string->num_chars; return cstr; }
int ws_utf8_append_char(WsUtf8String *string, unsigned long ch) { unsigned char *d; unsigned int num_bytes = WS_UTF8_ENC_TYPE(ch); unsigned int len, i; if (num_bytes == 0) ws_fatal("ws_utf8_append_char(): 0x%lx is not a valid UTF-8 character", ch); d = ws_realloc(string->data, string->len + num_bytes); if (d == NULL) return 0; len = string->len; /* Encode the continuation bytes (n > 1). */ for (i = num_bytes - 1; i > 0; i--) { d[len + i] = WS_UTF8_ENC_C_BITS; d[len + i] |= ch & WS_UTF8_CONT_DATA_MASK; ch >>= 6; } /* And continue the first byte. */ d[len] = utf8_hibits[num_bytes]; d[len] |= ch; string->data = d; string->len += num_bytes; string->num_chars++; return 1; }
static void remove_block(WsMemBlockHdr *b) { if (b->magic != MAGIC) ws_fatal("remove_block(): invalid magic\n"); if (b->next) b->next->prev = b->prev; if (b->prev) b->prev->next = b->next; else blocks = b->next; balance -= b->size; num_blocks--; memset(b, 0xfe, SIZE(b->size)); }
void ws_lexer_free_block(WsCompiler *compiler, void *ptr) { int i; if (ptr == NULL) return; for (i = compiler->lexer_active_list_size - 1; i >= 0; i--) { if (compiler->lexer_active_list[i] == ptr) { memmove(&compiler->lexer_active_list[i], &compiler->lexer_active_list[i + 1], (compiler->lexer_active_list_size - i - 1) * sizeof(void *)); compiler->lexer_active_list_size--; ws_free(ptr); return; } } ws_fatal("ws_lexer_free_block(): unknown block 0x%lx", (unsigned long) ptr); }
void ws_expr_linearize(WsCompiler *compiler, WsExpression *expr) { WsListItem *li; WsAsmIns *ins; switch (expr->type) { case WS_EXPR_COMMA: /* Linearize left. */ ws_expr_linearize(compiler, expr->u.comma.left); /* Pop its result. */ ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, WS_ASM_POP)); /* Linearize right */ ws_expr_linearize(compiler, expr->u.comma.right); break; case WS_EXPR_ASSIGN: { WsNamespace *ns = ws_variable_lookup(compiler, expr->u.assign.identifier); if (ns == NULL) { /* Unknown identifier. */ ws_src_error(compiler, expr->line, "unknown variable `%s'", expr->u.symbol); return; } if (expr->u.assign.op == '=') { /* Evaluate the expression. */ ws_expr_linearize(compiler, expr->u.assign.expr); /* Store the value to the variable. */ ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_P_STORE_VAR, ns->vindex)); } else if (expr->u.assign.op == tADDA) { /* Linearize the expression. */ ws_expr_linearize(compiler, expr->u.assign.expr); /* Add it to the variable. */ ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_ADD_ASG, ns->vindex)); } else if (expr->u.assign.op == tSUBA) { /* Linearize the expression. */ ws_expr_linearize(compiler, expr->u.assign.expr); /* Substract it from the variable. */ ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_SUB_ASG, ns->vindex)); } else { /* Load the old value from the variable. */ ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_P_LOAD_VAR, ns->vindex)); /* Evaluate the expression. */ ws_expr_linearize(compiler, expr->u.assign.expr); /* Perform the operand. */ ins = NULL; switch (expr->u.assign.op) { case tMULA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_MUL); break; case tDIVA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_DIV); break; case tREMA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_REM); break; case tADDA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_ADD); break; case tSUBA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_SUB); break; case tLSHIFTA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_LSHIFT); break; case tRSSHIFTA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_RSSHIFT); break; case tRSZSHIFTA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_RSZSHIFT); break; case tANDA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_AND); break; case tXORA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_XOR); break; case tORA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_OR); break; case tIDIVA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_IDIV); break; default: ws_fatal("ws_expr_linearize(): unknown assignment operand %x", expr->u.assign.op); break; } ws_asm_link(compiler, ins); /* Store the value to the variable. */ ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_P_STORE_VAR, ns->vindex)); } /* The value of the assignment expression is the value assigned. So, we must load the value from the variable. This would also be a good place for the `dup' operand but we lose since we don't have it. */ ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_P_LOAD_VAR, ns->vindex)); } break; case WS_EXPR_CONDITIONAL: { WsAsmIns *l_else = ws_asm_label(compiler, expr->line); WsAsmIns *l_end = ws_asm_label(compiler, expr->line); /* Linearize condition. */ ws_expr_linearize(compiler, expr->u.conditional.e_cond); /* If the result if false, jump to the else-branch. */ ws_asm_link(compiler, ws_asm_branch(compiler, expr->line, WS_ASM_P_TJUMP, l_else)); /* Linearize the then-expression and jump out. */ ws_expr_linearize(compiler, expr->u.conditional.e_then); ws_asm_link(compiler, ws_asm_branch(compiler, expr->line, WS_ASM_P_JUMP, l_end)); /* The else-branch. */ ws_asm_link(compiler, l_else); ws_expr_linearize(compiler, expr->u.conditional.e_else); /* Insert the end label. */ ws_asm_link(compiler, l_end); } break; case WS_EXPR_LOGICAL: { WsAsmIns *l_out = ws_asm_label(compiler, expr->line); /* Linearize the left-hand size expression. */ ws_expr_linearize(compiler, expr->u.logical.left); /* Short-circuit check. The type of the logical expression is the short-circuit byte-code operand. */ ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, expr->u.logical.type)); ws_asm_link(compiler, ws_asm_branch(compiler, expr->line, WS_ASM_P_TJUMP, l_out)); /* Linearize the right-hand size expression. */ ws_expr_linearize(compiler, expr->u.logical.right); /* The result of a logical expression should be boolean. * Control statements do automatic conversion, but typeof() * does not. */ ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, WS_ASM_TOBOOL)); /* Insert the end label. */ ws_asm_link(compiler, l_out); } break; case WS_EXPR_BINARY: /* Linearize left and right. */ ws_expr_linearize(compiler, expr->u.binary.left); ws_expr_linearize(compiler, expr->u.binary.right); /* The type of the binary expression is the byte-code opcode. */ ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, expr->u.binary.type)); break; case WS_EXPR_UNARY: /* Linearize the expression. */ ws_expr_linearize(compiler, expr->u.unary.expr); /* The type of the unary expression is the byte-code opcode. */ ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, expr->u.unary.type)); break; case WS_EXPR_UNARY_VAR: { WsNamespace *ns = ws_variable_lookup(compiler, expr->u.unary_var.variable); if (ns == NULL) { /* An unknown identifier. */ ws_src_error(compiler, expr->line, "unknown variable `%s'", expr->u.unary_var.variable); return; } /* First, do the operation. */ if (expr->u.unary_var.addp) ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_P_INCR_VAR, ns->vindex)); else ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_DECR_VAR, ns->vindex)); /* Second, load the new value of the variable. */ ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_P_LOAD_VAR, ns->vindex)); } break; case WS_EXPR_POSTFIX_VAR: { WsNamespace *ns = ws_variable_lookup(compiler, expr->u.postfix_var.variable); if (ns == NULL) { /* An unknown identifier. */ ws_src_error(compiler, expr->line, "unknown variable `%s'", expr->u.postfix_var.variable); return; } /* First, load the old value of the variable. */ ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_P_LOAD_VAR, ns->vindex)); /* Second, do the operation. */ if (expr->u.unary_var.addp) ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_P_INCR_VAR, ns->vindex)); else ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_DECR_VAR, ns->vindex)); } break; case WS_EXPR_CALL: /* First, evaluate the arguments. */ for (li = expr->u.call.arguments->head; li; li = li->next) ws_expr_linearize(compiler, li->data); /* Second, emit the call instruction. */ switch (expr->u.call.type) { case ' ': /* LocalScriptFunctionCall */ { WsFunctionHash *f = ws_function_hash(compiler, expr->u.call.name); if (f == NULL || !f->defined) { ws_src_error(compiler, expr->line, "unknown local function `%s'", expr->u.call.name); return; } /* Check that the function is called with correct amount of arguments. */ if (expr->u.call.arguments->num_items != compiler->functions[f->findex].params->num_items) { ws_src_error(compiler, expr->line, "invalid amount of arguments for `%s': " "expected %u, got %u", expr->u.call.name, compiler->functions[f->findex].params->num_items, expr->u.call.arguments->num_items); return; } /* Emit assembler. */ ws_asm_link(compiler, ws_asm_call(compiler, expr->line, f->findex)); } break; case '#': /* ExternalScriptFunctionCall */ { WsPragmaUse *use = ws_hash_get(compiler->pragma_use_hash, expr->u.call.base); WsUInt16 findex; if (use == NULL) { ws_src_error(compiler, expr->line, "unknown external compilation unit `%s'", expr->u.call.base); return; } /* Insert the function name to the byte-code pool. */ if (!ws_bc_add_const_utf8_string( compiler->bc, &findex, (unsigned char *) expr->u.call.name, strlen(expr->u.call.name))) { ws_error_memory(compiler); return; } /* Emit assembler. */ ws_asm_link(compiler, ws_asm_call_url(compiler, expr->line, findex, use->urlindex, expr->u.call.arguments->num_items)); } break; case '.': /* LibraryFunctionCall */ { WsUInt16 lindex; WsUInt8 findex; WsUInt8 num_args; WsBool lindex_found; WsBool findex_found; if (!ws_stdlib_function(expr->u.call.base, expr->u.call.name, &lindex, &findex, &num_args, &lindex_found, &findex_found)) { if (!lindex_found) ws_src_error(compiler, expr->line, "unknown system library `%s'", expr->u.call.base); else ws_src_error(compiler, expr->line, "unknown library function `%s.%s'", expr->u.call.base, expr->u.call.name); return; } /* Check the argument count. */ if (expr->u.call.arguments->num_items != num_args) { ws_src_error(compiler, expr->line, "invalid amount of arguments for `%s.%s': " "expected %u, got %u", expr->u.call.base, expr->u.call.name, num_args, expr->u.call.arguments->num_items); return; } /* Emit assembler. */ ws_asm_link(compiler, ws_asm_call_lib(compiler, expr->line, findex, lindex)); } break; default: ws_fatal("ws_expr_linearize(): unknown call expression type %x", expr->u.call.type); break; } break; case WS_EXPR_SYMBOL: { WsNamespace *ns = ws_variable_lookup(compiler, expr->u.symbol); if (ns == NULL) { /* An unknown identifier. */ ws_src_error(compiler, expr->line, "unknown variable `%s'", expr->u.symbol); return; } /* Create a load instruction for the variable. */ ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_P_LOAD_VAR, ns->vindex)); } break; case WS_EXPR_CONST_INVALID: ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, WS_ASM_CONST_INVALID)); break; case WS_EXPR_CONST_TRUE: ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, WS_ASM_CONST_TRUE)); break; case WS_EXPR_CONST_FALSE: ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, WS_ASM_CONST_FALSE)); break; case WS_EXPR_CONST_INTEGER: if (expr->u.integer.ival == 0) ins = ws_asm_ins(compiler, expr->line, WS_ASM_CONST_0); else if (expr->u.integer.ival == 1 && expr->u.integer.sign == 1) ins = ws_asm_ins(compiler, expr->line, WS_ASM_CONST_1); else { WsUInt16 cindex; WsInt32 ival; if (expr->u.integer.sign >= 0) { if (expr->u.integer.ival > (WsUInt32) WS_INT32_MAX) ws_src_error(compiler, expr->line, "integer literal too large"); ival = expr->u.integer.ival; } else { if (expr->u.integer.ival > (WsUInt32) WS_INT32_MAX + 1) ws_src_error(compiler, expr->line, "integer too small"); ival = - (WsInt32) expr->u.integer.ival; } if (!ws_bc_add_const_int(compiler->bc, &cindex, ival)) { ws_error_memory(compiler); return; } ins = ws_asm_load_const(compiler, expr->line, cindex); } ws_asm_link(compiler, ins); break; case WS_EXPR_CONST_FLOAT: { WsUInt16 cindex; if (!ws_bc_add_const_float(compiler->bc, &cindex, expr->u.fval)) { ws_error_memory(compiler); return; } ws_asm_link(compiler, ws_asm_load_const(compiler, expr->line, cindex)); } break; case WS_EXPR_CONST_STRING: if (expr->u.string.len == 0) ins = ws_asm_ins(compiler, expr->line, WS_ASM_CONST_ES); else { WsUInt16 cindex; if (!ws_bc_add_const_utf8_string(compiler->bc, &cindex, expr->u.string.data, expr->u.string.len)) { ws_error_memory(compiler); return; } ins = ws_asm_load_const(compiler, expr->line, cindex); } ws_asm_link(compiler, ins); break; } }
WsBool ws_encode_buffer(WsBuffer *buffer, ...) { va_list ap; WsEncodingSpec spec; int ival; unsigned char *p; unsigned char *cp; size_t len; WsUInt32 ui32; unsigned char data[64]; va_start(ap, buffer); while ((spec = va_arg(ap, int)) != WS_ENC_END) { switch (spec) { case WS_ENC_BYTE: case WS_ENC_INT8: case WS_ENC_UINT8: ival = va_arg(ap, int); if (!ws_buffer_append_space(buffer, &p, 1)) goto error; WS_PUT_UINT8(p, ival); break; case WS_ENC_INT16: case WS_ENC_UINT16: ival = va_arg(ap, int); if (!ws_buffer_append_space(buffer, &p, 2)) goto error; WS_PUT_UINT16(p, ival); break; case WS_ENC_INT32: case WS_ENC_UINT32: ival = va_arg(ap, long); if (!ws_buffer_append_space(buffer, &p, 4)) goto error; WS_PUT_UINT32(p, ival); break; case WS_ENC_MB_UINT16: case WS_ENC_MB_UINT32: if (spec == WS_ENC_MB_UINT16) ui32 = va_arg(ap, int); else ui32 = va_arg(ap, long); len = sizeof(data); cp = ws_encode_mb_uint32(ui32, data, &len); if (!ws_buffer_append_space(buffer, &p, len)) goto error; memcpy(p, cp, len); break; case WS_ENC_DATA: cp = va_arg(ap, unsigned char *); len = va_arg(ap, unsigned int); if (!ws_buffer_append_space(buffer, &p, len)) goto error; memcpy(p, cp, len); break; default: ws_fatal("ws_encode_buffer(): unknown type %d: probably a missing " "WS_ENC_END", spec); break; } }
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; }
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; }
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; }
void ws_asm_print(WsCompiler *compiler) { WsAsmIns *ins; for (ins = compiler->asm_head; ins; ins = ins->next) { if (ins->type > 0xff) { /* A symbolic operand. */ switch (ins->type) { case WS_ASM_P_LABEL: ws_fprintf(WS_STDOUT, ".L%d:\t\t\t\t/* refcount=%d */\n", ins->ws_label_idx, ins->ws_label_refcount); break; case WS_ASM_P_JUMP: ws_fprintf(WS_STDOUT, "\tjump*\t\tL%d\n", ins->ws_label->ws_label_idx); break; case WS_ASM_P_TJUMP: ws_fprintf(WS_STDOUT, "\ttjump*\t\tL%d\n", ins->ws_label->ws_label_idx); break; case WS_ASM_P_CALL: ws_fprintf(WS_STDOUT, "\tcall*\t\t%s\n", compiler->functions[ins->ws_findex].name); break; case WS_ASM_P_CALL_LIB: { const char *lib; const char *func; ws_stdlib_function_name(ins->ws_lindex, ins->ws_findex, &lib, &func); ws_fprintf(WS_STDOUT, "\tcall_lib*\t%s.%s\n", lib ? lib : "???", func ? func : "???"); } break; case WS_ASM_P_CALL_URL: ws_fprintf(WS_STDOUT, "\tcall_url*\t%u %u %u\n", ins->ws_lindex, ins->ws_findex, ins->ws_args); break; case WS_ASM_P_LOAD_VAR: ws_fprintf(WS_STDOUT, "\tload_var*\t%u\n", ins->ws_vindex); break; case WS_ASM_P_STORE_VAR: ws_fprintf(WS_STDOUT, "\tstore_var*\t%u\n", ins->ws_vindex); break; case WS_ASM_P_INCR_VAR: ws_fprintf(WS_STDOUT, "\tincr_var*\t%u\n", ins->ws_vindex); break; case WS_ASM_P_LOAD_CONST: ws_fprintf(WS_STDOUT, "\tload_const*\t%u\n", ins->ws_cindex); break; } } else { WsUInt8 op = WS_ASM_OP(ins->type); if (operands[op].name) { /* Operands add_asg and sub_asg are special. */ if (op == WS_ASM_ADD_ASG || op == WS_ASM_SUB_ASG) ws_fprintf(WS_STDOUT, "\t%s\t\t%u\n", operands[ins->type].name, ins->ws_vindex); else ws_fprintf(WS_STDOUT, "\t%s\n", operands[ins->type].name); } else ws_fatal("ws_asm_print(): unknown operand 0x%x", op); } } }