/* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2005 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
*
* wsasm.c
*
* Author: Markku Rossi
*
* Copyright (c) 1999-2000 WAPIT OY LTD.
* All rights reserved.
*
* Byte-code assembler.
*
*/
#include "wsint.h"
#include "wsasm.h"
#include "wsstdlib.h"
/********************* Macros to fetch items from BC operands ***********/
#define WS_OPNAME(op) (operands[(op)].name)
#define WS_OPSIZE(op) (operands[(op)].size)
/********************* Byte-code operands *******************************/
static struct
{
char *name;
int size;
} operands[256] = {
#include "wsopcodes.h"
};
/********************* Symbolic assembler instructions ******************/
/* General helpers. */
void ws_asm_link(WsCompiler *compiler, WsAsmIns *ins)
{
if (compiler->asm_tail) {
compiler->asm_tail->next = ins;
ins->prev = compiler->asm_tail;
compiler->asm_tail = ins;
} else
compiler->asm_tail = compiler->asm_head = ins;
}
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);
}
}
}
void ws_asm_dasm(WsCompilerPtr compiler, const unsigned char *code, size_t len)
{
size_t i = 0;
while (i < len) {
WsUInt8 byt = code[i];
WsUInt8 op;
WsUInt8 arg;
WsUInt8 i8, j8, k8;
WsUInt16 i16, j16;
op = WS_ASM_OP(byt);
arg = WS_ASM_ARG(byt);
ws_fprintf(WS_STDOUT, "%4x:\t%-16s", i, WS_OPNAME(op));
switch (op) {
/* The `short jumps'. */
case WS_ASM_JUMP_FW_S:
case WS_ASM_TJUMP_FW_S:
ws_fprintf(WS_STDOUT, "%x\n", i + WS_OPSIZE(op) + arg);
break;
case WS_ASM_JUMP_BW_S:
ws_fprintf(WS_STDOUT, "%x\n", i - arg);
break;
/* Jumps with WsUInt8 argument. */
case WS_ASM_JUMP_FW:
case WS_ASM_TJUMP_FW:
WS_GET_UINT8(code + i + 1, i8);
ws_fprintf(WS_STDOUT, "%x\n", i + WS_OPSIZE(op) + i8);
break;
case WS_ASM_JUMP_BW:
case WS_ASM_TJUMP_BW:
WS_GET_UINT8(code + i + 1, i8);
ws_fprintf(WS_STDOUT, "%x\n", i - i8);
break;
/* Jumps with wide argument. */
case WS_ASM_JUMP_FW_W:
case WS_ASM_TJUMP_FW_W:
WS_GET_UINT16(code + i + 1, i16);
ws_fprintf(WS_STDOUT, "%x\n", i + WS_OPSIZE(op) + i16);
break;
case WS_ASM_JUMP_BW_W:
case WS_ASM_TJUMP_BW_W:
WS_GET_UINT16(code + i + 1, i16);
ws_fprintf(WS_STDOUT, "%x\n", i - i16);
break;
/* The `short' opcodes. */
case WS_ASM_LOAD_VAR_S:
case WS_ASM_STORE_VAR_S:
case WS_ASM_INCR_VAR_S:
ws_fprintf(WS_STDOUT, "%d\n", arg);
break;
/* Local script function calls. */
case WS_ASM_CALL_S:
ws_fprintf(WS_STDOUT, "%d\n", arg);
break;
case WS_ASM_CALL:
WS_GET_UINT8(code + i + 1, i8);
ws_fprintf(WS_STDOUT, "%d\n", i8);
break;
/* Library calls. */
case WS_ASM_CALL_LIB_S:
case WS_ASM_CALL_LIB:
case WS_ASM_CALL_LIB_W:
{
WsUInt8 findex;
WsUInt16 lindex;
char lnamebuf[64];
char fnamebuf[64];
const char *lname;
const char *fname;
if (op == WS_ASM_CALL_LIB_S) {
WS_GET_UINT8(code + i + 1, lindex);
findex = arg;
} else if (op == WS_ASM_CALL_LIB) {
WS_GET_UINT8(code + i + 1, findex);
WS_GET_UINT8(code + i + 2, lindex);
} else {
WS_GET_UINT8(code + i + 1, findex);
WS_GET_UINT16(code + i + 2, lindex);
}
if (!ws_stdlib_function_name(lindex, findex, &lname, &fname)) {
snprintf(lnamebuf, sizeof(lnamebuf), "%d", lindex);
snprintf(fnamebuf, sizeof(lnamebuf), "%d", findex);
lname = lnamebuf;
fname = fnamebuf;
}
ws_fprintf(WS_STDOUT, "%s.%s\n", lname, fname);
}
break;
/* URL calls. */
case WS_ASM_CALL_URL:
WS_GET_UINT8(code + i + 1, i8);
WS_GET_UINT8(code + i + 2, j8);
WS_GET_UINT8(code + i + 3, k8);
ws_fprintf(WS_STDOUT, "%d.%d %d\n", i8, j8, k8);
break;
case WS_ASM_CALL_URL_W:
WS_GET_UINT16(code + i + 1, i16);
WS_GET_UINT16(code + i + 3, j16);
WS_GET_UINT8(code + i + 5, i8);
ws_fprintf(WS_STDOUT, "%d.%d %d\n", i16, j16, i8);
break;
/* Constant access. */
case WS_ASM_LOAD_CONST_S:
case WS_ASM_LOAD_CONST:
case WS_ASM_LOAD_CONST_W:
if (op == WS_ASM_LOAD_CONST_S)
i16 = arg;
else if (op == WS_ASM_LOAD_CONST) {
WS_GET_UINT8(code + i + 1, i8);
i16 = i8;
} else
WS_GET_UINT16(code + i + 1, i16);
ws_fprintf(WS_STDOUT, "%d\n", i16);
break;
/* Operands with WsUInt8 argument. */
case WS_ASM_LOAD_VAR:
case WS_ASM_STORE_VAR:
case WS_ASM_INCR_VAR:
case WS_ASM_DECR_VAR:
case WS_ASM_ADD_ASG:
case WS_ASM_SUB_ASG:
WS_GET_UINT8(code + i + 1, i8);
ws_fprintf(WS_STDOUT, "%d\n", i8);
break;
/* The trivial cases. */
default:
ws_fprintf(WS_STDOUT, "\n");
break;
}
i += WS_OPSIZE(op);
}
}
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;
}
/* Contructors for assembler instructions. */
static WsAsmIns *asm_alloc(WsCompiler *compiler, WsUInt16 type, WsUInt32 line)
{
WsAsmIns *ins = ws_f_calloc(compiler->pool_asm, 1, sizeof(*ins));
if (ins == NULL)
ws_error_memory(compiler);
else {
ins->type = type;
ins->line = line;
}
return ins;
}
WsAsmIns *ws_asm_label(WsCompiler *compiler, WsUInt32 line)
{
WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_LABEL, line);
if (ins)
ins->ws_label_idx = compiler->next_label++;
return ins;
}
WsAsmIns *ws_asm_branch(WsCompiler *compiler, WsUInt32 line, WsUInt16 inst,
WsAsmIns *label)
{
WsAsmIns *ins = asm_alloc(compiler, inst, line);
if (ins) {
ins->ws_label = label;
label->ws_label_refcount++;
}
return ins;
}
WsAsmIns *ws_asm_call(WsCompiler *compiler, WsUInt32 line, WsUInt8 findex)
{
WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_CALL, line);
if (ins)
ins->ws_findex = findex;
return ins;
}
WsAsmIns *ws_asm_call_lib(WsCompiler *compiler, WsUInt32 line, WsUInt8 findex,
WsUInt16 lindex)
{
WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_CALL_LIB, line);
if (ins) {
ins->ws_findex = findex;
ins->ws_lindex = lindex;
}
return ins;
}
WsAsmIns *ws_asm_call_url(WsCompiler *compiler, WsUInt32 line, WsUInt16 findex,
WsUInt16 urlindex, WsUInt8 args)
{
WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_CALL_URL, line);
if (ins) {
ins->ws_findex = findex;
ins->ws_lindex = urlindex;
ins->ws_args = args;
}
return ins;
}
WsAsmIns *ws_asm_variable(WsCompiler *compiler, WsUInt32 line, WsUInt16 inst,
WsUInt8 vindex)
{
WsAsmIns *ins = asm_alloc(compiler, inst, line);
if (ins)
ins->ws_vindex = vindex;
return ins;
}
WsAsmIns *ws_asm_load_const(WsCompiler *compiler, WsUInt32 line,
WsUInt16 cindex)
{
WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_LOAD_CONST, line);
if (ins)
ins->ws_cindex = cindex;
return ins;
}
WsAsmIns *ws_asm_ins(WsCompiler *compiler, WsUInt32 line, WsUInt8 opcode)
{
return asm_alloc(compiler, opcode, line);
}