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