1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2014 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  *    if any, must include the following acknowledgment:
22  *       "This product includes software developed by the
23  *        Kannel Group (http://www.kannel.org/)."
24  *    Alternately, this acknowledgment may appear in the software itself,
25  *    if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  *    endorse or promote products derived from this software without
29  *    prior written permission. For written permission, please
30  *    contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  *    nor may "Kannel" appear in their name, without prior written
34  *    permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group.  For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  *
59  * wsasm.c
60  *
61  * Author: Markku Rossi <mtr@iki.fi>
62  *
63  * Copyright (c) 1999-2000 WAPIT OY LTD.
64  *		 All rights reserved.
65  *
66  * Byte-code assembler.
67  *
68  */
69 
70 #include "wsint.h"
71 #include "wsasm.h"
72 #include "wsstdlib.h"
73 
74 /********************* Macros to fetch items from BC operands ***********/
75 
76 #define WS_OPNAME(op) (operands[(op)].name)
77 #define WS_OPSIZE(op) (operands[(op)].size)
78 
79 /********************* Byte-code operands *******************************/
80 
81 static struct
82 {
83     char *name;
84     int size;
85 } operands[256] = {
86 #include "wsopcodes.h"
87 };
88 
89 /********************* Symbolic assembler instructions ******************/
90 
91 /* General helpers. */
92 
ws_asm_link(WsCompiler * compiler,WsAsmIns * ins)93 void ws_asm_link(WsCompiler *compiler, WsAsmIns *ins)
94 {
95     if (compiler->asm_tail) {
96         compiler->asm_tail->next = ins;
97         ins->prev = compiler->asm_tail;
98 
99         compiler->asm_tail = ins;
100     } else
101         compiler->asm_tail = compiler->asm_head = ins;
102 }
103 
104 
ws_asm_print(WsCompiler * compiler)105 void ws_asm_print(WsCompiler *compiler)
106 {
107     WsAsmIns *ins;
108 
109     for (ins = compiler->asm_head; ins; ins = ins->next) {
110         if (ins->type > 0xff) {
111             /* A symbolic operand. */
112             switch (ins->type) {
113             case WS_ASM_P_LABEL:
114                 ws_fprintf(WS_STDOUT, ".L%d:\t\t\t\t/* refcount=%d */\n",
115                            ins->ws_label_idx, ins->ws_label_refcount);
116                 break;
117 
118             case WS_ASM_P_JUMP:
119                 ws_fprintf(WS_STDOUT, "\tjump*\t\tL%d\n",
120                            ins->ws_label->ws_label_idx);
121                 break;
122 
123             case WS_ASM_P_TJUMP:
124                 ws_fprintf(WS_STDOUT, "\ttjump*\t\tL%d\n",
125                            ins->ws_label->ws_label_idx);
126                 break;
127 
128             case WS_ASM_P_CALL:
129                 ws_fprintf(WS_STDOUT, "\tcall*\t\t%s\n",
130                            compiler->functions[ins->ws_findex].name);
131                 break;
132 
133             case WS_ASM_P_CALL_LIB:
134                 {
135                     const char *lib;
136                     const char *func;
137 
138                     ws_stdlib_function_name(ins->ws_lindex,
139                                             ins->ws_findex,
140                                             &lib, &func);
141                     ws_fprintf(WS_STDOUT, "\tcall_lib*\t%s.%s\n",
142                                lib ? lib : "???",
143                                func ? func : "???");
144                 }
145                 break;
146 
147             case WS_ASM_P_CALL_URL:
148                 ws_fprintf(WS_STDOUT, "\tcall_url*\t%u %u %u\n",
149                            ins->ws_lindex, ins->ws_findex, ins->ws_args);
150                 break;
151 
152             case WS_ASM_P_LOAD_VAR:
153                 ws_fprintf(WS_STDOUT, "\tload_var*\t%u\n", ins->ws_vindex);
154                 break;
155 
156             case WS_ASM_P_STORE_VAR:
157                 ws_fprintf(WS_STDOUT, "\tstore_var*\t%u\n", ins->ws_vindex);
158                 break;
159 
160             case WS_ASM_P_INCR_VAR:
161                 ws_fprintf(WS_STDOUT, "\tincr_var*\t%u\n", ins->ws_vindex);
162                 break;
163 
164             case WS_ASM_P_LOAD_CONST:
165                 ws_fprintf(WS_STDOUT, "\tload_const*\t%u\n", ins->ws_cindex);
166                 break;
167             }
168         } else {
169             WsUInt8 op = WS_ASM_OP(ins->type);
170 
171             if (operands[op].name) {
172                 /* Operands add_asg and sub_asg are special. */
173                 if (op == WS_ASM_ADD_ASG || op == WS_ASM_SUB_ASG)
174                     ws_fprintf(WS_STDOUT, "\t%s\t\t%u\n", operands[ins->type].name,
175                                ins->ws_vindex);
176                 else
177                     ws_fprintf(WS_STDOUT, "\t%s\n", operands[ins->type].name);
178             } else
179                 ws_fatal("ws_asm_print(): unknown operand 0x%x", op);
180         }
181     }
182 }
183 
184 
ws_asm_dasm(WsCompilerPtr compiler,const unsigned char * code,size_t len)185 void ws_asm_dasm(WsCompilerPtr compiler, const unsigned char *code, size_t len)
186 {
187     size_t i = 0;
188 
189     while (i < len) {
190         WsUInt8 byt = code[i];
191         WsUInt8 op;
192         WsUInt8 arg;
193         WsUInt8 i8, j8, k8;
194         WsUInt16 i16, j16;
195 
196         op = WS_ASM_OP(byt);
197         arg = WS_ASM_ARG(byt);
198 
199         ws_fprintf(WS_STDOUT, "%4x:\t%-16s", i, WS_OPNAME(op));
200 
201         switch (op) {
202             /* The `short jumps'. */
203         case WS_ASM_JUMP_FW_S:
204         case WS_ASM_TJUMP_FW_S:
205             ws_fprintf(WS_STDOUT, "%x\n", i + WS_OPSIZE(op) + arg);
206             break;
207 
208         case WS_ASM_JUMP_BW_S:
209             ws_fprintf(WS_STDOUT, "%x\n", i - arg);
210             break;
211 
212             /* Jumps with WsUInt8 argument. */
213         case WS_ASM_JUMP_FW:
214         case WS_ASM_TJUMP_FW:
215             WS_GET_UINT8(code + i + 1, i8);
216             ws_fprintf(WS_STDOUT, "%x\n", i + WS_OPSIZE(op) + i8);
217             break;
218 
219         case WS_ASM_JUMP_BW:
220         case WS_ASM_TJUMP_BW:
221             WS_GET_UINT8(code + i + 1, i8);
222             ws_fprintf(WS_STDOUT, "%x\n", i - i8);
223             break;
224 
225             /* Jumps with wide argument. */
226         case WS_ASM_JUMP_FW_W:
227         case WS_ASM_TJUMP_FW_W:
228             WS_GET_UINT16(code + i + 1, i16);
229             ws_fprintf(WS_STDOUT, "%x\n", i + WS_OPSIZE(op) + i16);
230             break;
231 
232         case WS_ASM_JUMP_BW_W:
233         case WS_ASM_TJUMP_BW_W:
234             WS_GET_UINT16(code + i + 1, i16);
235             ws_fprintf(WS_STDOUT, "%x\n", i - i16);
236             break;
237 
238             /* The `short' opcodes. */
239         case WS_ASM_LOAD_VAR_S:
240         case WS_ASM_STORE_VAR_S:
241         case WS_ASM_INCR_VAR_S:
242             ws_fprintf(WS_STDOUT, "%d\n", arg);
243             break;
244 
245             /* Local script function calls. */
246         case WS_ASM_CALL_S:
247             ws_fprintf(WS_STDOUT, "%d\n", arg);
248             break;
249 
250         case WS_ASM_CALL:
251             WS_GET_UINT8(code + i + 1, i8);
252             ws_fprintf(WS_STDOUT, "%d\n", i8);
253             break;
254 
255             /* Library calls. */
256         case WS_ASM_CALL_LIB_S:
257         case WS_ASM_CALL_LIB:
258         case WS_ASM_CALL_LIB_W:
259             {
260                 WsUInt8 findex;
261                 WsUInt16 lindex;
262                 char lnamebuf[64];
263                 char fnamebuf[64];
264                 const char *lname;
265                 const char *fname;
266 
267                 if (op == WS_ASM_CALL_LIB_S) {
268                     WS_GET_UINT8(code + i + 1, lindex);
269                     findex = arg;
270                 } else if (op == WS_ASM_CALL_LIB) {
271                     WS_GET_UINT8(code + i + 1, findex);
272                     WS_GET_UINT8(code + i + 2, lindex);
273                 } else {
274                     WS_GET_UINT8(code + i + 1, findex);
275                     WS_GET_UINT16(code + i + 2, lindex);
276                 }
277 
278                 if (!ws_stdlib_function_name(lindex, findex, &lname, &fname)) {
279                     snprintf(lnamebuf, sizeof(lnamebuf), "%d", lindex);
280                     snprintf(fnamebuf, sizeof(lnamebuf), "%d", findex);
281                     lname = lnamebuf;
282                     fname = fnamebuf;
283                 }
284                 ws_fprintf(WS_STDOUT, "%s.%s\n", lname, fname);
285             }
286             break;
287 
288             /* URL calls. */
289         case WS_ASM_CALL_URL:
290             WS_GET_UINT8(code + i + 1, i8);
291             WS_GET_UINT8(code + i + 2, j8);
292             WS_GET_UINT8(code + i + 3, k8);
293             ws_fprintf(WS_STDOUT, "%d.%d %d\n", i8, j8, k8);
294             break;
295 
296         case WS_ASM_CALL_URL_W:
297             WS_GET_UINT16(code + i + 1, i16);
298             WS_GET_UINT16(code + i + 3, j16);
299             WS_GET_UINT8(code + i + 5, i8);
300             ws_fprintf(WS_STDOUT, "%d.%d %d\n", i16, j16, i8);
301             break;
302 
303             /* Constant access. */
304         case WS_ASM_LOAD_CONST_S:
305         case WS_ASM_LOAD_CONST:
306         case WS_ASM_LOAD_CONST_W:
307             if (op == WS_ASM_LOAD_CONST_S)
308                 i16 = arg;
309             else if (op == WS_ASM_LOAD_CONST) {
310                 WS_GET_UINT8(code + i + 1, i8);
311                 i16 = i8;
312             } else
313                 WS_GET_UINT16(code + i + 1, i16);
314 
315             ws_fprintf(WS_STDOUT, "%d\n", i16);
316             break;
317 
318             /* Operands with WsUInt8 argument. */
319         case WS_ASM_LOAD_VAR:
320         case WS_ASM_STORE_VAR:
321         case WS_ASM_INCR_VAR:
322         case WS_ASM_DECR_VAR:
323         case WS_ASM_ADD_ASG:
324         case WS_ASM_SUB_ASG:
325             WS_GET_UINT8(code + i + 1, i8);
326             ws_fprintf(WS_STDOUT, "%d\n", i8);
327             break;
328 
329             /* The trivial cases. */
330         default:
331             ws_fprintf(WS_STDOUT, "\n");
332             break;
333         }
334 
335         i += WS_OPSIZE(op);
336     }
337 }
338 
339 
340 void
ws_asm_linearize(WsCompiler * compiler)341 ws_asm_linearize(WsCompiler *compiler)
342 {
343     WsAsmIns *ins;
344     WsBool process_again = WS_TRUE;
345 
346     /* Calculate all offsets and select real assembler instructions for
347        our internal pseudo instructions.  This is continued as long as
348        the code changes. */
349     while (process_again) {
350         WsUInt32 offset = 1;
351 
352         process_again = WS_FALSE;
353 
354         for (ins = compiler->asm_head; ins; ins = ins->next) {
355             ins->offset = offset;
356 
357             switch (ins->type) {
358             case WS_ASM_JUMP_FW_S:
359                 ins->ws_offset = (ins->ws_label->offset
360                                   - (offset + WS_OPSIZE(ins->type)));
361                 break;
362 
363             case WS_ASM_JUMP_FW:
364                 ins->ws_offset = (ins->ws_label->offset
365                                   - (offset + WS_OPSIZE(ins->type)));
366 
367                 if (ins->ws_offset <= 31) {
368                     ins->type = WS_ASM_JUMP_FW_S;
369                     process_again = WS_TRUE;
370                 }
371                 break;
372 
373             case WS_ASM_JUMP_FW_W:
374                 ins->ws_offset = (ins->ws_label->offset
375                                   - (offset + WS_OPSIZE(ins->type)));
376 
377                 if (ins->ws_offset <= 31) {
378                     ins->type = WS_ASM_JUMP_FW_S;
379                     process_again = WS_TRUE;
380                 } else if (ins->ws_offset <= 255) {
381                     ins->type = WS_ASM_JUMP_FW;
382                     process_again = WS_TRUE;
383                 }
384                 break;
385 
386             case WS_ASM_JUMP_BW_S:
387                 ins->ws_offset = offset - ins->ws_label->offset;
388                 break;
389 
390             case WS_ASM_JUMP_BW:
391                 ins->ws_offset = offset - ins->ws_label->offset;
392 
393                 if (ins->ws_offset <= 31) {
394                     ins->type = WS_ASM_JUMP_BW_S;
395                     process_again = WS_TRUE;
396                 }
397                 break;
398 
399             case WS_ASM_JUMP_BW_W:
400                 ins->ws_offset = offset - ins->ws_label->offset;
401 
402                 if (ins->ws_offset <= 31) {
403                     ins->type = WS_ASM_JUMP_BW_S;
404                     process_again = WS_TRUE;
405                 } else if (ins->ws_offset <= 255) {
406                     ins->type = WS_ASM_JUMP_BW;
407                     process_again = WS_TRUE;
408                 }
409                 break;
410 
411             case WS_ASM_TJUMP_FW_S:
412                 ins->ws_offset = (ins->ws_label->offset
413                                   - (offset + WS_OPSIZE(ins->type)));
414                 break;
415 
416             case WS_ASM_TJUMP_FW:
417                 ins->ws_offset = (ins->ws_label->offset
418                                   - (offset + WS_OPSIZE(ins->type)));
419 
420                 if (ins->ws_offset <= 31) {
421                     ins->type = WS_ASM_TJUMP_FW_S;
422                     process_again = WS_TRUE;
423                 }
424                 break;
425 
426             case WS_ASM_TJUMP_FW_W:
427                 ins->ws_offset = (ins->ws_label->offset
428                                   - (offset + WS_OPSIZE(ins->type)));
429 
430                 if (ins->ws_offset <= 31) {
431                     ins->type = WS_ASM_TJUMP_FW_S;
432                     process_again = WS_TRUE;
433                 } else if (ins->ws_offset <= 255) {
434                     ins->type = WS_ASM_TJUMP_FW;
435                     process_again = WS_TRUE;
436                 }
437                 break;
438 
439             case WS_ASM_TJUMP_BW:
440                  ins->ws_offset = offset - ins->ws_label->offset;
441                  break;
442 
443             case WS_ASM_TJUMP_BW_W:
444                 ins->ws_offset = offset - ins->ws_label->offset;
445 
446                 if (ins->ws_offset <= 255) {
447                     ins->type = WS_ASM_TJUMP_BW;
448                     process_again = WS_TRUE;
449                 }
450                 break;
451 
452                 /*
453                  * The pseudo instructions.
454                  */
455 
456             case WS_ASM_P_LABEL:
457                 /* Nothing here. */
458                 break;
459 
460             case WS_ASM_P_JUMP:
461                 if (ins->ws_label->offset == 0) {
462                     /* A forward jump.  Let's assume the widest form. */
463                     ins->type = WS_ASM_JUMP_FW_W;
464                 } else {
465                     ins->ws_offset = offset - ins->ws_label->offset;
466 
467                     /* Jump backwards. */
468                     if (ins->ws_offset <= 31) {
469                         ins->type = WS_ASM_JUMP_BW_S;
470                     } else if (ins->ws_offset <= 255) {
471                         ins->type = WS_ASM_JUMP_BW;
472                     } else {
473                         ins->type = WS_ASM_JUMP_BW_W;
474                     }
475                 }
476                 break;
477 
478             case WS_ASM_P_TJUMP:
479                 if (ins->ws_label->offset == 0) {
480                     /* A forward jump.  Let's assume the widest form. */
481                     ins->type = WS_ASM_TJUMP_FW_W;
482                     process_again = WS_TRUE;
483                 } else {
484                     ins->ws_offset = offset - ins->ws_label->offset;
485 
486                     /* Jump backwards. */
487                     if (ins->ws_offset <= 255) {
488                         ins->type = WS_ASM_TJUMP_BW;
489                     } else {
490                         ins->type = WS_ASM_TJUMP_BW_W;
491                     }
492                 }
493                 break;
494 
495             case WS_ASM_P_CALL:
496                 if (ins->ws_findex <= 7) {
497                     /* The most compact form. */
498                     ins->type = WS_ASM_CALL_S;
499                 } else {
500                     /* The wider form. */
501                     ins->type = WS_ASM_CALL;
502                 }
503                 break;
504 
505             case WS_ASM_P_CALL_LIB:
506                 if (ins->ws_findex <= 7 && ins->ws_lindex <= 255) {
507                     /* The most compact form. */
508                     ins->type = WS_ASM_CALL_LIB_S;
509                 } else if (ins->ws_findex <= 255 && ins->ws_lindex <= 255) {
510                     /* The quite compact form. */
511                     ins->type = WS_ASM_CALL_LIB;
512                 } else {
513                     /* The most liberal form. */
514                     ins->type = WS_ASM_CALL_LIB_W;
515                 }
516                 break;
517 
518             case WS_ASM_P_CALL_URL:
519                 if (ins->ws_findex <= 255 && ins->ws_lindex <= 255)
520                     /* The compact form. */
521                     ins->type = WS_ASM_CALL_URL;
522                 else
523                     ins->type = WS_ASM_CALL_URL_W;
524                 break;
525 
526             case WS_ASM_P_LOAD_VAR:
527                 if (ins->ws_vindex <= 31)
528                     /* The compact form. */
529                     ins->type = WS_ASM_LOAD_VAR_S;
530                 else
531                     ins->type = WS_ASM_LOAD_VAR;
532                 break;
533 
534             case WS_ASM_P_STORE_VAR:
535                 if (ins->ws_vindex <= 15)
536                     ins->type = WS_ASM_STORE_VAR_S;
537                 else
538                     ins->type = WS_ASM_STORE_VAR;
539                 break;
540 
541             case WS_ASM_P_INCR_VAR:
542                 if (ins->ws_vindex <= 7)
543                     ins->type = WS_ASM_INCR_VAR_S;
544                 else
545                     ins->type = WS_ASM_INCR_VAR;
546                 break;
547 
548             case WS_ASM_P_LOAD_CONST:
549                 if (ins->ws_cindex <= 15)
550                     ins->type = WS_ASM_LOAD_CONST_S;
551                 else if (ins->ws_cindex <= 255)
552                     ins->type = WS_ASM_LOAD_CONST;
553                 else
554                     ins->type = WS_ASM_LOAD_CONST_W;
555                 break;
556             }
557 
558             gw_assert(ins->type == WS_ASM_P_LABEL || ins->type < 0x100);
559 
560             if (ins->type != WS_ASM_P_LABEL) {
561                 gw_assert(operands[ins->type].name != NULL);
562                 offset += operands[ins->type].size;
563             }
564         }
565     }
566 
567     /* Ok, ready to linearize the byte-code. */
568     for (ins = compiler->asm_head; ins; ins = ins->next) {
569         if (ins->type == WS_ASM_P_LABEL)
570             continue;
571 
572         gw_assert(ins->type <= 0xff);
573 
574         switch (ins->type) {
575         case WS_ASM_JUMP_FW_S:
576         case WS_ASM_JUMP_BW_S:
577         case WS_ASM_TJUMP_FW_S:
578             if (!ws_encode_buffer(&compiler->byte_code,
579                                   WS_ENC_BYTE,
580                                   WS_ASM_GLUE(ins->type, ins->ws_offset),
581                                   WS_ENC_END))
582                 goto error;
583             break;
584 
585         case WS_ASM_JUMP_FW:
586         case WS_ASM_JUMP_BW:
587         case WS_ASM_TJUMP_FW:
588         case WS_ASM_TJUMP_BW:
589             if (!ws_encode_buffer(&compiler->byte_code,
590                                   WS_ENC_BYTE, ins->type,
591                                   WS_ENC_UINT8, (WsUInt8) ins->ws_offset,
592                                   WS_ENC_END))
593                 goto error;
594             break;
595 
596         case WS_ASM_JUMP_FW_W:
597         case WS_ASM_JUMP_BW_W:
598         case WS_ASM_TJUMP_FW_W:
599         case WS_ASM_TJUMP_BW_W:
600             if (!ws_encode_buffer(&compiler->byte_code,
601                                   WS_ENC_BYTE, ins->type,
602                                   WS_ENC_UINT16, (WsUInt16) ins->ws_offset,
603                                   WS_ENC_END))
604                 goto error;
605             break;
606 
607         case WS_ASM_CALL_S:
608             if (!ws_encode_buffer(&compiler->byte_code,
609                                   WS_ENC_BYTE,
610                                   WS_ASM_GLUE(ins->type, ins->ws_findex),
611                                   WS_ENC_END))
612                 goto error;
613             break;
614 
615         case WS_ASM_CALL:
616             if (!ws_encode_buffer(&compiler->byte_code,
617                                   WS_ENC_BYTE, (WsByte) ins->type,
618                                   WS_ENC_UINT8, (WsUInt8) ins->ws_findex,
619                                   WS_ENC_END))
620                 goto error;
621             break;
622 
623         case WS_ASM_CALL_LIB_S:
624             if (!ws_encode_buffer(&compiler->byte_code,
625                                   WS_ENC_BYTE,
626                                   WS_ASM_GLUE(ins->type, ins->ws_findex),
627                                   WS_ENC_UINT8, (WsUInt8) ins->ws_lindex,
628                                   WS_ENC_END))
629                 goto error;
630             break;
631 
632         case WS_ASM_CALL_LIB:
633             if (!ws_encode_buffer(&compiler->byte_code,
634                                   WS_ENC_BYTE, (WsByte) ins->type,
635                                   WS_ENC_UINT8, (WsUInt8) ins->ws_findex,
636                                   WS_ENC_UINT8, (WsUInt8) ins->ws_lindex,
637                                   WS_ENC_END))
638                 goto error;
639             break;
640 
641         case WS_ASM_CALL_LIB_W:
642             if (!ws_encode_buffer(&compiler->byte_code,
643                                   WS_ENC_BYTE, (WsByte) ins->type,
644                                   WS_ENC_UINT8, (WsUInt8) ins->ws_findex,
645                                   WS_ENC_UINT16, (WsUInt16) ins->ws_lindex,
646                                   WS_ENC_END))
647                 goto error;
648             break;
649 
650         case WS_ASM_CALL_URL:
651             if (!ws_encode_buffer(&compiler->byte_code,
652                                   WS_ENC_BYTE, (WsByte) ins->type,
653                                   WS_ENC_UINT8, (WsUInt8) ins->ws_lindex,
654                                   WS_ENC_UINT8, (WsUInt8) ins->ws_findex,
655                                   WS_ENC_UINT8, (WsUInt8) ins->ws_args,
656                                   WS_ENC_END))
657                 goto error;
658             break;
659 
660         case WS_ASM_CALL_URL_W:
661             if (!ws_encode_buffer(&compiler->byte_code,
662                                   WS_ENC_BYTE, (WsByte) ins->type,
663                                   WS_ENC_UINT16, (WsUInt16) ins->ws_lindex,
664                                   WS_ENC_UINT16, (WsUInt16) ins->ws_findex,
665                                   WS_ENC_UINT8, (WsUInt8) ins->ws_args,
666                                   WS_ENC_END))
667                 goto error;
668             break;
669 
670         case WS_ASM_LOAD_VAR_S:
671         case WS_ASM_STORE_VAR_S:
672             if (!ws_encode_buffer(&compiler->byte_code,
673                                   WS_ENC_BYTE,
674                                   WS_ASM_GLUE(ins->type, ins->ws_vindex),
675                                   WS_ENC_END))
676                 goto error;
677             break;
678 
679         case WS_ASM_LOAD_VAR:
680         case WS_ASM_STORE_VAR:
681             if (!ws_encode_buffer(&compiler->byte_code,
682                                   WS_ENC_BYTE, (WsByte) ins->type,
683                                   WS_ENC_UINT8, (WsUInt8) ins->ws_vindex,
684                                   WS_ENC_END))
685                 goto error;
686             break;
687 
688         case WS_ASM_INCR_VAR_S:
689             if (!ws_encode_buffer(&compiler->byte_code,
690                                   WS_ENC_BYTE,
691                                   WS_ASM_GLUE(ins->type, ins->ws_vindex),
692                                   WS_ENC_END))
693                 goto error;
694             break;
695 
696         case WS_ASM_INCR_VAR:
697         case WS_ASM_DECR_VAR:
698             if (!ws_encode_buffer(&compiler->byte_code,
699                                   WS_ENC_BYTE, (WsByte) ins->type,
700                                   WS_ENC_UINT8, (WsUInt8) ins->ws_vindex,
701                                   WS_ENC_END))
702                 goto error;
703             break;
704 
705         case WS_ASM_LOAD_CONST_S:
706             if (!ws_encode_buffer(&compiler->byte_code,
707                                   WS_ENC_BYTE,
708                                   WS_ASM_GLUE(ins->type, ins->ws_cindex),
709                                   WS_ENC_END))
710                 goto error;
711             break;
712 
713         case WS_ASM_LOAD_CONST:
714             if (!ws_encode_buffer(&compiler->byte_code,
715                                   WS_ENC_BYTE, (WsByte) ins->type,
716                                   WS_ENC_UINT8, (WsUInt8) ins->ws_cindex,
717                                   WS_ENC_END))
718                 goto error;
719             break;
720 
721         case WS_ASM_LOAD_CONST_W:
722             if (!ws_encode_buffer(&compiler->byte_code,
723                                   WS_ENC_BYTE, (WsByte) ins->type,
724                                   WS_ENC_UINT16, (WsUInt16) ins->ws_cindex,
725                                   WS_ENC_END))
726                 goto error;
727             break;
728 
729         case WS_ASM_ADD_ASG:
730         case WS_ASM_SUB_ASG:
731             if (!ws_encode_buffer(&compiler->byte_code,
732                                   WS_ENC_BYTE, (WsByte) ins->type,
733                                   WS_ENC_UINT8, (WsUInt8) ins->ws_vindex,
734                                   WS_ENC_END))
735                 goto error;
736             break;
737 
738         case WS_ASM_CONST_0:
739         case WS_ASM_CONST_1:
740         case WS_ASM_CONST_M1:
741         case WS_ASM_CONST_ES:
742         case WS_ASM_CONST_INVALID:
743         case WS_ASM_CONST_TRUE:
744         case WS_ASM_CONST_FALSE:
745         case WS_ASM_INCR:
746         case WS_ASM_DECR:
747         case WS_ASM_UMINUS:
748         case WS_ASM_ADD:
749         case WS_ASM_SUB:
750         case WS_ASM_MUL:
751         case WS_ASM_DIV:
752         case WS_ASM_IDIV:
753         case WS_ASM_REM:
754         case WS_ASM_B_AND:
755         case WS_ASM_B_OR:
756         case WS_ASM_B_XOR:
757         case WS_ASM_B_NOT:
758         case WS_ASM_B_LSHIFT:
759         case WS_ASM_B_RSSHIFT:
760         case WS_ASM_B_RSZSHIFT:
761         case WS_ASM_EQ:
762         case WS_ASM_LE:
763         case WS_ASM_LT:
764         case WS_ASM_GE:
765         case WS_ASM_GT:
766         case WS_ASM_NE:
767         case WS_ASM_NOT:
768         case WS_ASM_SCAND:
769         case WS_ASM_SCOR:
770         case WS_ASM_TOBOOL:
771         case WS_ASM_POP:
772         case WS_ASM_TYPEOF:
773         case WS_ASM_ISVALID:
774         case WS_ASM_RETURN:
775         case WS_ASM_RETURN_ES:
776         case WS_ASM_DEBUG:
777             if (!ws_encode_buffer(&compiler->byte_code,
778                                   WS_ENC_BYTE, (WsByte) ins->type,
779                                   WS_ENC_END))
780                 goto error;
781             break;
782 
783         default:
784             ws_fatal("ws_asm_linearize(): unknown instruction 0x%02x",
785                      ins->type);
786             break;
787         }
788     }
789 
790     /*
791      * Avoid generating 0-length functions, because not all clients
792      * handle them correctly.
793      */
794     if (ws_buffer_len(&compiler->byte_code) == 0) {
795 	if (!ws_encode_buffer(&compiler->byte_code,
796 	   		      WS_ENC_BYTE, (WsByte) WS_ASM_RETURN_ES,
797 			      WS_ENC_END))
798 	    goto error;
799     }
800 
801     return;
802 
803     /*
804      * Error handling.
805      */
806 
807 error:
808 
809     ws_error_memory(compiler);
810     return;
811 }
812 
813 
814 /* Contructors for assembler instructions. */
815 
asm_alloc(WsCompiler * compiler,WsUInt16 type,WsUInt32 line)816 static WsAsmIns *asm_alloc(WsCompiler *compiler, WsUInt16 type, WsUInt32 line)
817 {
818     WsAsmIns *ins = ws_f_calloc(compiler->pool_asm, 1, sizeof(*ins));
819 
820     if (ins == NULL)
821         ws_error_memory(compiler);
822     else {
823         ins->type = type;
824         ins->line = line;
825     }
826 
827     return ins;
828 }
829 
830 
ws_asm_label(WsCompiler * compiler,WsUInt32 line)831 WsAsmIns *ws_asm_label(WsCompiler *compiler, WsUInt32 line)
832 {
833     WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_LABEL, line);
834 
835     if (ins)
836         ins->ws_label_idx = compiler->next_label++;
837 
838     return ins;
839 }
840 
841 
ws_asm_branch(WsCompiler * compiler,WsUInt32 line,WsUInt16 inst,WsAsmIns * label)842 WsAsmIns *ws_asm_branch(WsCompiler *compiler, WsUInt32 line, WsUInt16 inst,
843                         WsAsmIns *label)
844 {
845     WsAsmIns *ins = asm_alloc(compiler, inst, line);
846 
847     if (ins) {
848         ins->ws_label = label;
849         label->ws_label_refcount++;
850     }
851 
852     return ins;
853 }
854 
855 
ws_asm_call(WsCompiler * compiler,WsUInt32 line,WsUInt8 findex)856 WsAsmIns *ws_asm_call(WsCompiler *compiler, WsUInt32 line, WsUInt8 findex)
857 {
858     WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_CALL, line);
859 
860     if (ins)
861         ins->ws_findex = findex;
862 
863     return ins;
864 }
865 
866 
ws_asm_call_lib(WsCompiler * compiler,WsUInt32 line,WsUInt8 findex,WsUInt16 lindex)867 WsAsmIns *ws_asm_call_lib(WsCompiler *compiler, WsUInt32 line, WsUInt8 findex,
868                 WsUInt16 lindex)
869 {
870     WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_CALL_LIB, line);
871 
872     if (ins) {
873         ins->ws_findex = findex;
874         ins->ws_lindex = lindex;
875     }
876 
877     return ins;
878 }
879 
880 
ws_asm_call_url(WsCompiler * compiler,WsUInt32 line,WsUInt16 findex,WsUInt16 urlindex,WsUInt8 args)881 WsAsmIns *ws_asm_call_url(WsCompiler *compiler, WsUInt32 line, WsUInt16 findex,
882                           WsUInt16 urlindex, WsUInt8 args)
883 {
884     WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_CALL_URL, line);
885 
886     if (ins) {
887         ins->ws_findex = findex;
888         ins->ws_lindex = urlindex;
889         ins->ws_args = args;
890     }
891 
892     return ins;
893 }
894 
895 
ws_asm_variable(WsCompiler * compiler,WsUInt32 line,WsUInt16 inst,WsUInt8 vindex)896 WsAsmIns *ws_asm_variable(WsCompiler *compiler, WsUInt32 line, WsUInt16 inst,
897                           WsUInt8 vindex)
898 {
899     WsAsmIns *ins = asm_alloc(compiler, inst, line);
900 
901     if (ins)
902         ins->ws_vindex = vindex;
903 
904     return ins;
905 }
906 
907 
ws_asm_load_const(WsCompiler * compiler,WsUInt32 line,WsUInt16 cindex)908 WsAsmIns *ws_asm_load_const(WsCompiler *compiler, WsUInt32 line,
909                             WsUInt16 cindex)
910 {
911     WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_LOAD_CONST, line);
912 
913     if (ins)
914         ins->ws_cindex = cindex;
915 
916     return ins;
917 }
918 
919 
ws_asm_ins(WsCompiler * compiler,WsUInt32 line,WsUInt8 opcode)920 WsAsmIns *ws_asm_ins(WsCompiler *compiler, WsUInt32 line, WsUInt8 opcode)
921 {
922     return asm_alloc(compiler, opcode, line);
923 }
924