source: mainline/uspace/app/sbi/src/run.c@ 3061bc1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3061bc1 was 1b20da0, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

style: Remove trailing whitespace on non-empty lines, in certain file types.

Command used: tools/srepl '\([^[:space:]]\)\s\+$' '\1' -- *.c *.h *.py *.sh *.s *.S *.ag

  • Property mode set to 100644
File size: 50.1 KB
Line 
1/*
2 * Copyright (c) 2011 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @file Runner (executes the code). */
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <assert.h>
34#include "bigint.h"
35#include "builtin.h"
36#include "cspan.h"
37#include "debug.h"
38#include "intmap.h"
39#include "list.h"
40#include "mytypes.h"
41#include "rdata.h"
42#include "run_expr.h"
43#include "run_texpr.h"
44#include "stree.h"
45#include "strtab.h"
46#include "symbol.h"
47#include "tdata.h"
48
49#include "run.h"
50
51static void run_block(run_t *run, stree_block_t *block);
52static void run_exps(run_t *run, stree_exps_t *exps, rdata_item_t **res);
53static void run_vdecl(run_t *run, stree_vdecl_t *vdecl);
54static void run_if(run_t *run, stree_if_t *if_s);
55static void run_switch(run_t *run, stree_switch_t *switch_s);
56static void run_while(run_t *run, stree_while_t *while_s);
57static void run_raise(run_t *run, stree_raise_t *raise_s);
58static void run_break(run_t *run, stree_break_t *break_s);
59static void run_return(run_t *run, stree_return_t *return_s);
60static void run_wef(run_t *run, stree_wef_t *wef_s);
61
62static bool_t run_exc_match(run_t *run, stree_except_t *except_c);
63static stree_csi_t *run_exc_payload_get_csi(run_t *run);
64
65static rdata_var_t *run_aprop_get_tpos(run_t *run, rdata_address_t *aprop);
66
67static void run_aprop_read(run_t *run, rdata_addr_prop_t *addr_prop,
68 rdata_item_t **ritem);
69static void run_aprop_write(run_t *run, rdata_addr_prop_t *addr_prop,
70 rdata_value_t *value);
71
72static void run_var_new_tprimitive(run_t *run, tdata_primitive_t *tprimitive,
73 rdata_var_t **rvar);
74static void run_var_new_null_ref(run_t *run, rdata_var_t **rvar);
75static void run_var_new_deleg(run_t *run, rdata_var_t **rvar);
76static void run_var_new_enum(run_t *run, tdata_enum_t *tenum,
77 rdata_var_t **rvar);
78
79/** Initialize runner instance.
80 *
81 * @param run Runner object
82 */
83void run_init(run_t *run)
84{
85 (void) run;
86}
87
88/** Run program.
89 *
90 * Associates the program @a prog with the runner object and executes
91 * it. If a run-time error occurs during the execution (e.g. an unhandled
92 * exception), @a run->error will be set to @c b_true when this function
93 * returns.
94 *
95 * @param run Runner object
96 * @param prog Program to run
97 */
98void run_program(run_t *run, stree_program_t *prog)
99{
100 stree_symbol_t *main_fun_sym;
101 stree_fun_t *main_fun;
102 rdata_var_t *main_obj;
103 stree_ident_t *fake_ident;
104 list_t main_args;
105 run_proc_ar_t *proc_ar;
106 rdata_item_t *res;
107
108 /* Note down link to program code. */
109 run->program = prog;
110
111 /* Initialize thread activation record. */
112 run->thread_ar = run_thread_ar_new();
113 list_init(&run->thread_ar->proc_ar);
114 run->thread_ar->bo_mode = bm_none;
115
116 /* Initialize global data structure. */
117 run_gdata_init(run);
118
119 /*
120 * Find entry point @c Main().
121 */
122 fake_ident = stree_ident_new();
123 fake_ident->sid = strtab_get_sid("Main");
124 main_fun_sym = symbol_find_epoint(prog, fake_ident);
125 if (main_fun_sym == NULL) {
126 printf("Error: Entry point 'Main' not found.\n");
127 exit(1);
128 }
129
130 main_fun = symbol_to_fun(main_fun_sym);
131 assert(main_fun != NULL);
132
133 main_obj = run_fun_sobject_find(run, main_fun);
134
135#ifdef DEBUG_RUN_TRACE
136 printf("Found function '"); symbol_print_fqn(main_fun_sym);
137 printf("'.\n");
138#endif
139
140 /* Run function @c main. */
141 list_init(&main_args);
142 run_proc_ar_create(run, main_obj, main_fun->proc, &proc_ar);
143 run_proc_ar_set_args(run, proc_ar, &main_args);
144 run_proc(run, proc_ar, &res);
145 run_proc_ar_destroy(run, proc_ar);
146
147 run_exc_check_unhandled(run);
148}
149
150/** Initialize global data.
151 *
152 * @param run Runner object
153 */
154void run_gdata_init(run_t *run)
155{
156 rdata_object_t *gobject;
157
158 run->gdata = rdata_var_new(vc_object);
159 gobject = rdata_object_new();
160 run->gdata->u.object_v = gobject;
161
162 gobject->class_sym = NULL;
163 gobject->static_obj = sn_static;
164 intmap_init(&gobject->fields);
165}
166
167/** Run procedure.
168 *
169 * Inserts the provided procedure AR @a proc_ar on the execution stack
170 * (in the thread AR) and executes the procedure. The return value
171 * of the procedure is stored to *(@a res). @c NULL is stored if the
172 * procedure returns no value.
173 *
174 * If the procedure execution bails out due to an exception, this
175 * can be determined by looking at @c bo_mode in thread AR. Also,
176 * in this case @c NULL is stored into *(@a res).
177 *
178 * @param run Runner object
179 * @param proc_ar Procedure activation record
180 * @param res Place to store procedure return value
181 */
182void run_proc(run_t *run, run_proc_ar_t *proc_ar, rdata_item_t **res)
183{
184 stree_proc_t *proc;
185 list_node_t *node;
186
187 proc = proc_ar->proc;
188
189#ifdef DEBUG_RUN_TRACE
190 printf("Start executing function '");
191 symbol_print_fqn(proc->outer_symbol);
192 printf("'.\n");
193#endif
194 /* Add procedure AR to the stack. */
195 list_append(&run->thread_ar->proc_ar, proc_ar);
196
197 /* Run main procedure block. */
198 if (proc->body != NULL) {
199 run_block(run, proc->body);
200 } else {
201 builtin_run_proc(run, proc);
202 }
203
204 /* Handle bailout. */
205 switch (run->thread_ar->bo_mode) {
206 case bm_stat:
207 /* Break bailout was not caught. */
208 assert(b_false);
209 /* Fallthrough */
210 case bm_proc:
211 run->thread_ar->bo_mode = bm_none;
212 break;
213 default:
214 break;
215 }
216
217#ifdef DEBUG_RUN_TRACE
218 printf("Done executing procedure '");
219 symbol_print_fqn(proc->outer_symbol);
220 printf("'.\n");
221
222 run_print_fun_bt(run);
223#endif
224 /* Remove procedure activation record from the stack. */
225 node = list_last(&run->thread_ar->proc_ar);
226 assert(list_node_data(node, run_proc_ar_t *) == proc_ar);
227 list_remove(&run->thread_ar->proc_ar, node);
228
229 /* Procedure should not return an address. */
230 assert(proc_ar->retval == NULL || proc_ar->retval->ic == ic_value);
231 *res = proc_ar->retval;
232}
233
234/** Run code block.
235 *
236 * @param run Runner object
237 * @param block Block to run
238 */
239static void run_block(run_t *run, stree_block_t *block)
240{
241 run_proc_ar_t *proc_ar;
242 run_block_ar_t *block_ar;
243 list_node_t *node;
244 stree_stat_t *stat;
245
246#ifdef DEBUG_RUN_TRACE
247 printf("Executing one code block.\n");
248#endif
249
250 /* Create block activation record. */
251 block_ar = run_block_ar_new();
252 intmap_init(&block_ar->vars);
253
254 /* Add block activation record to the stack. */
255 proc_ar = run_get_current_proc_ar(run);
256 list_append(&proc_ar->block_ar, block_ar);
257
258 node = list_first(&block->stats);
259 while (node != NULL) {
260 stat = list_node_data(node, stree_stat_t *);
261 run_stat(run, stat, NULL);
262
263 if (run->thread_ar->bo_mode != bm_none)
264 break;
265
266 node = list_next(&block->stats, node);
267 }
268
269#ifdef DEBUG_RUN_TRACE
270 printf("Done executing code block.\n");
271#endif
272
273 /* Remove block activation record from the stack. */
274 node = list_last(&proc_ar->block_ar);
275 assert(list_node_data(node, run_block_ar_t *) == block_ar);
276 list_remove(&proc_ar->block_ar, node);
277
278 /* Deallocate block activation record. */
279 run_block_ar_destroy(run, block_ar);
280}
281
282/** Run statement.
283 *
284 * Executes a statement. If @a res is not NULL and the statement is an
285 * expression statement with a value, the value item will be stored to
286 * @a res.
287 *
288 * @param run Runner object
289 * @param stat Statement to run
290 * @param res Place to store exps result or NULL if not interested
291 */
292void run_stat(run_t *run, stree_stat_t *stat, rdata_item_t **res)
293{
294#ifdef DEBUG_RUN_TRACE
295 printf("Executing one statement %p.\n", stat);
296#endif
297
298 if (res != NULL)
299 *res = NULL;
300
301 switch (stat->sc) {
302 case st_exps:
303 run_exps(run, stat->u.exp_s, res);
304 break;
305 case st_vdecl:
306 run_vdecl(run, stat->u.vdecl_s);
307 break;
308 case st_if:
309 run_if(run, stat->u.if_s);
310 break;
311 case st_switch:
312 run_switch(run, stat->u.switch_s);
313 break;
314 case st_while:
315 run_while(run, stat->u.while_s);
316 break;
317 case st_raise:
318 run_raise(run, stat->u.raise_s);
319 break;
320 case st_break:
321 run_break(run, stat->u.break_s);
322 break;
323 case st_return:
324 run_return(run, stat->u.return_s);
325 break;
326 case st_wef:
327 run_wef(run, stat->u.wef_s);
328 break;
329 case st_for:
330 printf("Ignoring unimplemented statement type %d.\n", stat->sc);
331 break;
332 }
333}
334
335/** Run expression statement.
336 *
337 * Executes an expression statement. If @a res is not NULL then the value
338 * of the expression (or NULL if it has no value) will be stored to @a res.
339 *
340 * @param run Runner object
341 * @param exps Expression statement to run
342 * @param res Place to store exps result or NULL if not interested
343 */
344static void run_exps(run_t *run, stree_exps_t *exps, rdata_item_t **res)
345{
346 rdata_item_t *rexpr;
347
348#ifdef DEBUG_RUN_TRACE
349 printf("Executing expression statement.\n");
350#endif
351 run_expr(run, exps->expr, &rexpr);
352
353 /*
354 * If the expression has a value, the caller should have asked for it.
355 */
356 assert(res != NULL || rexpr == NULL);
357
358 if (res != NULL)
359 *res = rexpr;
360}
361
362/** Run variable declaration statement.
363 *
364 * @param run Runner object
365 * @param vdecl Variable declaration statement to run
366 */
367static void run_vdecl(run_t *run, stree_vdecl_t *vdecl)
368{
369 run_block_ar_t *block_ar;
370 rdata_var_t *var, *old_var;
371
372#ifdef DEBUG_RUN_TRACE
373 printf("Executing variable declaration statement.\n");
374#endif
375 /* Create variable and initialize with default value. */
376 run_var_new(run, vdecl->titem, &var);
377
378 block_ar = run_get_current_block_ar(run);
379 old_var = (rdata_var_t *) intmap_get(&block_ar->vars, vdecl->name->sid);
380
381 if (old_var != NULL) {
382 printf("Error: Duplicate variable '%s'\n",
383 strtab_get_str(vdecl->name->sid));
384 exit(1);
385 }
386
387 intmap_set(&block_ar->vars, vdecl->name->sid, var);
388
389#ifdef DEBUG_RUN_TRACE
390 printf("Declared variable '%s'\n", strtab_get_str(vdecl->name->sid));
391#endif
392}
393
394/** Run @c if statement.
395 *
396 * @param run Runner object
397 * @param if_s If statement to run
398 */
399static void run_if(run_t *run, stree_if_t *if_s)
400{
401 rdata_item_t *rcond;
402 list_node_t *ifc_node;
403 stree_if_clause_t *ifc;
404 bool_t rcond_b, clause_fired;
405
406#ifdef DEBUG_RUN_TRACE
407 printf("Executing if statement.\n");
408#endif
409 clause_fired = b_false;
410 ifc_node = list_first(&if_s->if_clauses);
411
412 /* Walk through all if/elif clauses and see if they fire. */
413
414 while (ifc_node != NULL) {
415 /* Get if/elif clause */
416 ifc = list_node_data(ifc_node, stree_if_clause_t *);
417
418 run_expr(run, ifc->cond, &rcond);
419 if (run_is_bo(run))
420 return;
421
422 rcond_b = run_item_boolean_value(run, rcond);
423 rdata_item_destroy(rcond);
424
425 if (rcond_b == b_true) {
426#ifdef DEBUG_RUN_TRACE
427 printf("Taking non-default path.\n");
428#endif
429 run_block(run, ifc->block);
430 clause_fired = b_true;
431 break;
432 }
433
434 ifc_node = list_next(&if_s->if_clauses, ifc_node);
435 }
436
437 /* If no if/elif clause fired, invoke the else clause. */
438 if (clause_fired == b_false && if_s->else_block != NULL) {
439#ifdef DEBUG_RUN_TRACE
440 printf("Taking default path.\n");
441#endif
442 run_block(run, if_s->else_block);
443 }
444
445#ifdef DEBUG_RUN_TRACE
446 printf("If statement terminated.\n");
447#endif
448}
449
450/** Run @c switch statement.
451 *
452 * @param run Runner object
453 * @param switch_s Switch statement to run
454 */
455static void run_switch(run_t *run, stree_switch_t *switch_s)
456{
457 rdata_item_t *rsexpr, *rsexpr_vi;
458 rdata_item_t *rwexpr, *rwexpr_vi;
459 list_node_t *whenc_node;
460 stree_when_t *whenc;
461 list_node_t *expr_node;
462 stree_expr_t *expr;
463 bool_t clause_fired;
464 bool_t equal;
465
466#ifdef DEBUG_RUN_TRACE
467 printf("Executing switch statement.\n");
468#endif
469 rsexpr_vi = NULL;
470
471 /* Evaluate switch expression */
472 run_expr(run, switch_s->expr, &rsexpr);
473 if (run_is_bo(run))
474 goto cleanup;
475
476 /* Convert to value item */
477 run_cvt_value_item(run, rsexpr, &rsexpr_vi);
478 rdata_item_destroy(rsexpr);
479 if (run_is_bo(run))
480 goto cleanup;
481
482 clause_fired = b_false;
483 whenc_node = list_first(&switch_s->when_clauses);
484
485 /* Walk through all when clauses and see if they fire. */
486
487 while (whenc_node != NULL) {
488 /* Get when clause */
489 whenc = list_node_data(whenc_node, stree_when_t *);
490
491 expr_node = list_first(&whenc->exprs);
492
493 /* Walk through all expressions in the when clause */
494 while (expr_node != NULL) {
495 /* Get expression */
496 expr = list_node_data(expr_node, stree_expr_t *);
497
498 /* Evaluate expression */
499 run_expr(run, expr, &rwexpr);
500 if (run_is_bo(run))
501 goto cleanup;
502
503 /* Convert to value item */
504 run_cvt_value_item(run, rwexpr, &rwexpr_vi);
505 rdata_item_destroy(rwexpr);
506 if (run_is_bo(run)) {
507 rdata_item_destroy(rwexpr_vi);
508 goto cleanup;
509 }
510
511 /* Check if values are equal ('==') */
512 run_equal(run, rsexpr_vi->u.value,
513 rwexpr_vi->u.value, &equal);
514 rdata_item_destroy(rwexpr_vi);
515 if (run_is_bo(run))
516 goto cleanup;
517
518 if (equal) {
519#ifdef DEBUG_RUN_TRACE
520 printf("Taking non-default path.\n");
521#endif
522 run_block(run, whenc->block);
523 clause_fired = b_true;
524 break;
525 }
526
527 expr_node = list_next(&whenc->exprs, expr_node);
528 }
529
530 if (clause_fired)
531 break;
532
533 whenc_node = list_next(&switch_s->when_clauses, whenc_node);
534 }
535
536 /* If no when clause fired, invoke the else clause. */
537 if (clause_fired == b_false && switch_s->else_block != NULL) {
538#ifdef DEBUG_RUN_TRACE
539 printf("Taking default path.\n");
540#endif
541 run_block(run, switch_s->else_block);
542 }
543cleanup:
544 if (rsexpr_vi != NULL)
545 rdata_item_destroy(rsexpr_vi);
546
547#ifdef DEBUG_RUN_TRACE
548 printf("Switch statement terminated.\n");
549#endif
550}
551
552/** Run @c while statement.
553 *
554 * @param run Runner object
555 * @param while_s While statement to run
556 */
557static void run_while(run_t *run, stree_while_t *while_s)
558{
559 rdata_item_t *rcond;
560
561#ifdef DEBUG_RUN_TRACE
562 printf("Executing while statement.\n");
563#endif
564 run_expr(run, while_s->cond, &rcond);
565 if (run_is_bo(run))
566 return;
567
568 while (run_item_boolean_value(run, rcond) == b_true) {
569 rdata_item_destroy(rcond);
570 run_block(run, while_s->body);
571 run_expr(run, while_s->cond, &rcond);
572 if (run_is_bo(run))
573 break;
574 }
575
576 if (rcond != NULL)
577 rdata_item_destroy(rcond);
578
579 if (run->thread_ar->bo_mode == bm_stat) {
580 /* Bailout due to break statement */
581 run->thread_ar->bo_mode = bm_none;
582 }
583
584#ifdef DEBUG_RUN_TRACE
585 printf("While statement terminated.\n");
586#endif
587}
588
589/** Run @c raise statement.
590 *
591 * @param run Runner object
592 * @param raise_s Raise statement to run
593 */
594static void run_raise(run_t *run, stree_raise_t *raise_s)
595{
596 rdata_item_t *rexpr;
597 rdata_item_t *rexpr_vi;
598
599#ifdef DEBUG_RUN_TRACE
600 printf("Executing raise statement.\n");
601#endif
602 run_expr(run, raise_s->expr, &rexpr);
603 if (run_is_bo(run))
604 return;
605
606 run_cvt_value_item(run, rexpr, &rexpr_vi);
607 rdata_item_destroy(rexpr);
608 if (run_is_bo(run))
609 return;
610
611 /* Store expression cspan in thread AR. */
612 run->thread_ar->exc_cspan = raise_s->expr->cspan;
613
614 /* Store expression result in thread AR. */
615 /* XXX rexpr_vi is leaked here, we only return ->u.value */
616 run->thread_ar->exc_payload = rexpr_vi->u.value;
617
618 /* Start exception bailout. */
619 run->thread_ar->bo_mode = bm_exc;
620}
621
622/** Run @c break statement.
623 *
624 * Forces control to return from the active breakable statement by setting
625 * bailout mode to @c bm_stat.
626 *
627 * @param run Runner object
628 * @param break_s Break statement to run
629 */
630static void run_break(run_t *run, stree_break_t *break_s)
631{
632#ifdef DEBUG_RUN_TRACE
633 printf("Executing 'break' statement.\n");
634#endif
635 (void) break_s;
636
637 /* Force control to ascend and leave the procedure. */
638 if (run->thread_ar->bo_mode == bm_none)
639 run->thread_ar->bo_mode = bm_stat;
640}
641
642/** Run @c return statement.
643 *
644 * Sets the return value in procedure AR and forces control to return
645 * from the function by setting bailout mode to @c bm_proc.
646 *
647 * @param run Runner object
648 * @param return_s Return statement to run
649 */
650static void run_return(run_t *run, stree_return_t *return_s)
651{
652 rdata_item_t *rexpr;
653 rdata_item_t *rexpr_vi;
654 run_proc_ar_t *proc_ar;
655
656#ifdef DEBUG_RUN_TRACE
657 printf("Executing return statement.\n");
658#endif
659 if (return_s->expr != NULL) {
660 run_expr(run, return_s->expr, &rexpr);
661 if (run_is_bo(run))
662 return;
663
664 run_cvt_value_item(run, rexpr, &rexpr_vi);
665 rdata_item_destroy(rexpr);
666 if (run_is_bo(run))
667 return;
668
669 /* Store expression result in procedure AR. */
670 proc_ar = run_get_current_proc_ar(run);
671 proc_ar->retval = rexpr_vi;
672 }
673
674 /* Force control to ascend and leave the procedure. */
675 if (run->thread_ar->bo_mode == bm_none)
676 run->thread_ar->bo_mode = bm_proc;
677}
678
679/** Run @c with-except-finally statement.
680 *
681 * Note: 'With' clause is not implemented.
682 *
683 * @param run Runner object
684 * @param wef_s With-except-finally statement to run
685 */
686static void run_wef(run_t *run, stree_wef_t *wef_s)
687{
688 list_node_t *except_n;
689 stree_except_t *except_c;
690 rdata_value_t *exc_payload;
691 run_bailout_mode_t bo_mode;
692
693#ifdef DEBUG_RUN_TRACE
694 printf("Executing with-except-finally statement.\n");
695#endif
696 run_block(run, wef_s->with_block);
697
698 if (run->thread_ar->bo_mode == bm_exc) {
699#ifdef DEBUG_RUN_TRACE
700 printf("With statement detected exception.\n");
701#endif
702 /* Reset to normal execution. */
703 run->thread_ar->bo_mode = bm_none;
704
705 /* Look for an except block. */
706 except_n = list_first(&wef_s->except_clauses);
707 while (except_n != NULL) {
708 except_c = list_node_data(except_n, stree_except_t *);
709 if (run_exc_match(run, except_c))
710 break;
711
712 except_n = list_next(&wef_s->except_clauses, except_n);
713 }
714
715 /* If one was found, execute it. */
716 if (except_n != NULL)
717 run_block(run, except_c->block);
718
719 /* Execute finally block */
720 if (wef_s->finally_block != NULL) {
721 /* Put exception on the side temporarily. */
722 bo_mode = run->thread_ar->bo_mode;
723 exc_payload = run->thread_ar->exc_payload;
724
725 run->thread_ar->bo_mode = bm_none;
726 run->thread_ar->exc_payload = NULL;
727
728 run_block(run, wef_s->finally_block);
729
730 if (bo_mode == bm_exc) {
731 /*
732 * Restore the original exception. If another
733 * exception occured in the finally block (i.e.
734 * double fault), it is forgotten.
735 */
736 run->thread_ar->bo_mode = bm_exc;
737 run->thread_ar->exc_payload = exc_payload;
738 }
739 }
740 }
741
742#ifdef DEBUG_RUN_TRACE
743 printf("With-except-finally statement terminated.\n");
744#endif
745}
746
747/** Determine whether currently active exception matches @c except clause.
748 *
749 * Checks if the currently active exception in the runner object @c run
750 * matches except clause @c except_c.
751 *
752 * @param run Runner object
753 * @param except_c @c except clause
754 * @return @c b_true if there is a match, @c b_false otherwise
755 */
756static bool_t run_exc_match(run_t *run, stree_except_t *except_c)
757{
758 stree_csi_t *exc_csi;
759
760 /* Get CSI of active exception. */
761 exc_csi = run_exc_payload_get_csi(run);
762
763 /* Determine if active exc. is derived from type in exc. clause. */
764 /* XXX This is wrong, it does not work with generics. */
765 return tdata_is_csi_derived_from_ti(exc_csi, except_c->titem);
766}
767
768/** Return CSI of the active exception.
769 *
770 * @param run Runner object
771 * @return CSI of the active exception
772 */
773static stree_csi_t *run_exc_payload_get_csi(run_t *run)
774{
775 rdata_value_t *payload;
776 rdata_var_t *payload_v;
777 rdata_object_t *payload_o;
778
779 payload = run->thread_ar->exc_payload;
780 assert(payload != NULL);
781
782 if (payload->var->vc != vc_ref) {
783 /* XXX Prevent this via static type checking. */
784 printf("Error: Exception payload must be an object "
785 "(found type %d).\n", payload->var->vc);
786 exit(1);
787 }
788
789 payload_v = payload->var->u.ref_v->vref;
790 if (payload_v->vc != vc_object) {
791 /* XXX Prevent this via static type checking. */
792 printf("Error: Exception payload must be an object "
793 "(found type %d).\n", payload_v->vc);
794 exit(1);
795 }
796
797 payload_o = payload_v->u.object_v;
798
799#ifdef DEBUG_RUN_TRACE
800 printf("Active exception: '");
801 symbol_print_fqn(payload_o->class_sym);
802 printf("'.\n");
803#endif
804 assert(payload_o->class_sym != NULL);
805 assert(payload_o->class_sym->sc == sc_csi);
806
807 return payload_o->class_sym->u.csi;
808}
809
810
811/** Check for unhandled exception.
812 *
813 * Checks whether there is an active exception. If so, it prints an
814 * error message and raises a run-time error.
815 *
816 * @param run Runner object
817 */
818void run_exc_check_unhandled(run_t *run)
819{
820 stree_csi_t *exc_csi;
821
822 if (run->thread_ar->bo_mode != bm_none) {
823 assert(run->thread_ar->bo_mode == bm_exc);
824
825 exc_csi = run_exc_payload_get_csi(run);
826
827 if (run->thread_ar->exc_cspan != NULL) {
828 cspan_print(run->thread_ar->exc_cspan);
829 putchar(' ');
830 }
831
832 printf("Error: Unhandled exception '");
833 symbol_print_fqn(csi_to_symbol(exc_csi));
834 printf("'.\n");
835
836 run_raise_error(run);
837 }
838}
839
840/** Raise an irrecoverable run-time error, start bailing out.
841 *
842 * Raises an error that cannot be handled by the user program.
843 *
844 * @param run Runner object
845 */
846void run_raise_error(run_t *run)
847{
848 run->thread_ar->bo_mode = bm_error;
849 run->thread_ar->error = b_true;
850}
851
852/** Construct a special recovery item.
853 *
854 * @param run Runner object
855 */
856rdata_item_t *run_recovery_item(run_t *run)
857{
858 (void) run;
859 return NULL;
860}
861
862/** Find a local variable in the currently active function.
863 *
864 * @param run Runner object
865 * @param name Name SID of the local variable
866 * @return Pointer to var node or @c NULL if not found
867 */
868rdata_var_t *run_local_vars_lookup(run_t *run, sid_t name)
869{
870 run_proc_ar_t *proc_ar;
871 run_block_ar_t *block_ar;
872 rdata_var_t *var;
873 list_node_t *node;
874
875 proc_ar = run_get_current_proc_ar(run);
876 node = list_last(&proc_ar->block_ar);
877
878 /* Walk through all block activation records. */
879 while (node != NULL) {
880 block_ar = list_node_data(node, run_block_ar_t *);
881 var = intmap_get(&block_ar->vars, name);
882 if (var != NULL)
883 return var;
884
885 node = list_prev(&proc_ar->block_ar, node);
886 }
887
888 /* No match */
889 return NULL;
890}
891
892/** Get current procedure activation record.
893 *
894 * @param run Runner object
895 * @return Active procedure AR
896 */
897run_proc_ar_t *run_get_current_proc_ar(run_t *run)
898{
899 list_node_t *node;
900
901 node = list_last(&run->thread_ar->proc_ar);
902 return list_node_data(node, run_proc_ar_t *);
903}
904
905/** Get current block activation record.
906 *
907 * @param run Runner object
908 * @return Active block AR
909 */
910run_block_ar_t *run_get_current_block_ar(run_t *run)
911{
912 run_proc_ar_t *proc_ar;
913 list_node_t *node;
914
915 proc_ar = run_get_current_proc_ar(run);
916
917 node = list_last(&proc_ar->block_ar);
918 return list_node_data(node, run_block_ar_t *);
919}
920
921/** Get current CSI.
922 *
923 * @param run Runner object
924 * @return Active CSI
925 */
926stree_csi_t *run_get_current_csi(run_t *run)
927{
928 run_proc_ar_t *proc_ar;
929
930 proc_ar = run_get_current_proc_ar(run);
931 return proc_ar->proc->outer_symbol->outer_csi;
932}
933
934/** Get static object (i.e. class object).
935 *
936 * Looks for a child static object named @a name in static object @a pobject.
937 * If the child does not exist yet, it is created.
938 *
939 * @param run Runner object
940 * @param csi CSI of the static object named @a name
941 * @param pobject Parent static object
942 * @param name Static object name
943 *
944 * @return Static (class) object of the given name
945 */
946rdata_var_t *run_sobject_get(run_t *run, stree_csi_t *csi,
947 rdata_var_t *pobj_var, sid_t name)
948{
949 rdata_object_t *pobject;
950 rdata_var_t *mbr_var;
951 rdata_var_t *rvar;
952 stree_ident_t *ident;
953
954 assert(pobj_var->vc == vc_object);
955 pobject = pobj_var->u.object_v;
956#ifdef DEBUG_RUN_TRACE
957 printf("Get static object '%s' in '", strtab_get_str(name));
958 if (pobject->class_sym != NULL)
959 symbol_print_fqn(pobject->class_sym);
960 else
961 printf("global");
962#endif
963
964 assert(pobject->static_obj == sn_static);
965
966 mbr_var = intmap_get(&pobject->fields, name);
967 if (mbr_var != NULL) {
968#ifdef DEBUG_RUN_TRACE
969 printf("Return exising static object (mbr_var=%p).\n", mbr_var);
970#endif
971 /* Return existing object. */
972 return mbr_var;
973 }
974
975 /* Construct new object. */
976#ifdef DEBUG_RUN_TRACE
977 printf("Construct new static object.\n");
978#endif
979 ident = stree_ident_new();
980 ident->sid = name;
981
982 run_new_csi_inst(run, csi, sn_static, &rvar);
983
984 /* Store static object reference for future use. */
985 intmap_set(&pobject->fields, name, rvar);
986
987 return rvar;
988}
989
990/** Get static object for CSI.
991 *
992 * In situations where we do not have the parent static object and need
993 * to find static object for a CSI from the gdata root we use this.
994 *
995 * This is only used in special cases such as when invoking the entry
996 * point. This is too slow to use during normal execution.
997 *
998 * @param run Runner object
999 * @param csi CSI to get static object of
1000 *
1001 * @return Static (class) object
1002 */
1003rdata_var_t *run_sobject_find(run_t *run, stree_csi_t *csi)
1004{
1005 rdata_var_t *pobj_var;
1006
1007 if (csi == NULL)
1008 return run->gdata;
1009
1010 assert(csi->ancr_state == ws_visited);
1011 pobj_var = run_sobject_find(run, csi_to_symbol(csi)->outer_csi);
1012
1013 return run_sobject_get(run, csi, pobj_var, csi->name->sid);
1014}
1015
1016/** Get static object for CSI containing function.
1017 *
1018 * This is used to obtain active object for invoking static function
1019 * @a fun. Only used in cases where we don't already have the object such
1020 * as when running the entry point. Otherwise this would be slow.
1021 *
1022 * @param run Runner object
1023 * @param fun Function to get static class object of
1024 *
1025 * @return Static (class) object
1026 */
1027rdata_var_t *run_fun_sobject_find(run_t *run, stree_fun_t *fun)
1028{
1029 return run_sobject_find(run, fun_to_symbol(fun)->outer_csi);
1030}
1031
1032/** Construct variable from a value item.
1033 *
1034 * XXX This should be in fact implemented using existing code as:
1035 *
1036 * (1) Create a variable of the desired type.
1037 * (2) Initialize the variable with the provided value.
1038 *
1039 * @param item Value item (initial value for variable).
1040 * @param var Place to store new var node.
1041 */
1042void run_value_item_to_var(rdata_item_t *item, rdata_var_t **var)
1043{
1044 rdata_bool_t *bool_v;
1045 rdata_char_t *char_v;
1046 rdata_deleg_t *deleg_v;
1047 rdata_enum_t *enum_v;
1048 rdata_int_t *int_v;
1049 rdata_string_t *string_v;
1050 rdata_ref_t *ref_v;
1051 rdata_var_t *in_var;
1052
1053 assert(item->ic == ic_value);
1054 in_var = item->u.value->var;
1055
1056 switch (in_var->vc) {
1057 case vc_bool:
1058 *var = rdata_var_new(vc_bool);
1059 bool_v = rdata_bool_new();
1060
1061 (*var)->u.bool_v = bool_v;
1062 bool_v->value = item->u.value->var->u.bool_v->value;
1063 break;
1064 case vc_char:
1065 *var = rdata_var_new(vc_char);
1066 char_v = rdata_char_new();
1067
1068 (*var)->u.char_v = char_v;
1069 bigint_clone(&item->u.value->var->u.char_v->value,
1070 &char_v->value);
1071 break;
1072 case vc_deleg:
1073 *var = rdata_var_new(vc_deleg);
1074 deleg_v = rdata_deleg_new();
1075
1076 (*var)->u.deleg_v = deleg_v;
1077 deleg_v->obj = item->u.value->var->u.deleg_v->obj;
1078 deleg_v->sym = item->u.value->var->u.deleg_v->sym;
1079 break;
1080 case vc_enum:
1081 *var = rdata_var_new(vc_enum);
1082 enum_v = rdata_enum_new();
1083
1084 (*var)->u.enum_v = enum_v;
1085 enum_v->value = item->u.value->var->u.enum_v->value;
1086 break;
1087 case vc_int:
1088 *var = rdata_var_new(vc_int);
1089 int_v = rdata_int_new();
1090
1091 (*var)->u.int_v = int_v;
1092 bigint_clone(&item->u.value->var->u.int_v->value,
1093 &int_v->value);
1094 break;
1095 case vc_string:
1096 *var = rdata_var_new(vc_string);
1097 string_v = rdata_string_new();
1098
1099 (*var)->u.string_v = string_v;
1100 string_v->value = item->u.value->var->u.string_v->value;
1101 break;
1102 case vc_ref:
1103 *var = rdata_var_new(vc_ref);
1104 ref_v = rdata_ref_new();
1105
1106 (*var)->u.ref_v = ref_v;
1107 ref_v->vref = item->u.value->var->u.ref_v->vref;
1108 break;
1109 default:
1110 printf("Error: Unimplemented argument type.\n");
1111 exit(1);
1112
1113 }
1114}
1115
1116/** Construct a procedure AR.
1117 *
1118 * @param run Runner object
1119 * @param obj Object whose procedure is being activated
1120 * @param proc Procedure that is being activated
1121 * @param rproc_ar Place to store pointer to new activation record
1122 */
1123void run_proc_ar_create(run_t *run, rdata_var_t *obj, stree_proc_t *proc,
1124 run_proc_ar_t **rproc_ar)
1125{
1126 run_proc_ar_t *proc_ar;
1127 run_block_ar_t *block_ar;
1128
1129 (void) run;
1130
1131 /* Create procedure activation record. */
1132 proc_ar = run_proc_ar_new();
1133 proc_ar->obj = obj;
1134 proc_ar->proc = proc;
1135 list_init(&proc_ar->block_ar);
1136
1137 proc_ar->retval = NULL;
1138
1139 /* Create special block activation record to hold function arguments. */
1140 block_ar = run_block_ar_new();
1141 intmap_init(&block_ar->vars);
1142 list_append(&proc_ar->block_ar, block_ar);
1143
1144 *rproc_ar = proc_ar;
1145}
1146
1147/** Destroy a procedure AR.
1148 *
1149 * @param run Runner object
1150 * @param proc_ar Pointer to procedure activation record
1151 */
1152void run_proc_ar_destroy(run_t *run, run_proc_ar_t *proc_ar)
1153{
1154 list_node_t *ar_node;
1155 run_block_ar_t *block_ar;
1156
1157 (void) run;
1158
1159 /* Destroy special block activation record. */
1160 ar_node = list_first(&proc_ar->block_ar);
1161 block_ar = list_node_data(ar_node, run_block_ar_t *);
1162 list_remove(&proc_ar->block_ar, ar_node);
1163 run_block_ar_destroy(run, block_ar);
1164
1165 /* Destroy procedure activation record. */
1166 proc_ar->obj = NULL;
1167 proc_ar->proc = NULL;
1168 list_fini(&proc_ar->block_ar);
1169 proc_ar->retval = NULL;
1170 run_proc_ar_delete(proc_ar);
1171}
1172
1173
1174/** Fill arguments in a procedure AR.
1175 *
1176 * When invoking a procedure this is used to store the argument values
1177 * in the activation record.
1178 *
1179 * @param run Runner object
1180 * @param proc_ar Existing procedure activation record where to store
1181 * the values
1182 * @param arg_vals List of value items (rdata_item_t *) -- real
1183 * argument values
1184 */
1185void run_proc_ar_set_args(run_t *run, run_proc_ar_t *proc_ar, list_t *arg_vals)
1186{
1187 stree_ctor_t *ctor;
1188 stree_fun_t *fun;
1189 stree_prop_t *prop;
1190 list_t *args;
1191 stree_proc_arg_t *varg;
1192 stree_symbol_t *outer_symbol;
1193
1194 run_block_ar_t *block_ar;
1195 list_node_t *block_ar_n;
1196 list_node_t *rarg_n, *parg_n;
1197 list_node_t *cn;
1198 rdata_item_t *rarg;
1199 stree_proc_arg_t *parg;
1200 rdata_var_t *var;
1201 rdata_var_t *ref_var;
1202 rdata_ref_t *ref;
1203 rdata_array_t *array;
1204 rdata_var_t *elem_var;
1205 int n_vargs, idx;
1206
1207 (void) run;
1208
1209 /* AR should have been created with run_proc_ar_create(). */
1210 assert(proc_ar->proc != NULL);
1211 outer_symbol = proc_ar->proc->outer_symbol;
1212
1213 /* Make compiler happy. */
1214 args = NULL;
1215 varg = NULL;
1216
1217 /*
1218 * The procedure being activated should belong to a member function or
1219 * property getter/setter.
1220 */
1221 switch (outer_symbol->sc) {
1222 case sc_ctor:
1223 ctor = symbol_to_ctor(outer_symbol);
1224 args = &ctor->sig->args;
1225 varg = ctor->sig->varg;
1226 break;
1227 case sc_fun:
1228 fun = symbol_to_fun(outer_symbol);
1229 args = &fun->sig->args;
1230 varg = fun->sig->varg;
1231 break;
1232 case sc_prop:
1233 prop = symbol_to_prop(outer_symbol);
1234 args = &prop->args;
1235 varg = prop->varg;
1236 break;
1237 case sc_csi:
1238 case sc_deleg:
1239 case sc_enum:
1240 case sc_var:
1241 assert(b_false);
1242 }
1243
1244 /* Fetch first block activation record. */
1245 block_ar_n = list_first(&proc_ar->block_ar);
1246 assert(block_ar_n != NULL);
1247 block_ar = list_node_data(block_ar_n, run_block_ar_t *);
1248
1249 /* Declare local variables to hold argument values. */
1250 rarg_n = list_first(arg_vals);
1251 parg_n = list_first(args);
1252
1253 while (parg_n != NULL) {
1254 if (rarg_n == NULL) {
1255 printf("Error: Too few arguments to '");
1256 symbol_print_fqn(outer_symbol);
1257 printf("'.\n");
1258 exit(1);
1259 }
1260
1261 rarg = list_node_data(rarg_n, rdata_item_t *);
1262 parg = list_node_data(parg_n, stree_proc_arg_t *);
1263
1264 assert(rarg->ic == ic_value);
1265
1266 /* Construct a variable from the argument value. */
1267 run_value_item_to_var(rarg, &var);
1268
1269 /* Declare variable using name of formal argument. */
1270 intmap_set(&block_ar->vars, parg->name->sid, var);
1271
1272 rarg_n = list_next(arg_vals, rarg_n);
1273 parg_n = list_next(args, parg_n);
1274 }
1275
1276 if (varg != NULL) {
1277 /* Function is variadic. Count number of variadic arguments. */
1278 cn = rarg_n;
1279 n_vargs = 0;
1280 while (cn != NULL) {
1281 n_vargs += 1;
1282 cn = list_next(arg_vals, cn);
1283 }
1284
1285 /* Prepare array to store variadic arguments. */
1286 array = rdata_array_new(1);
1287 array->extent[0] = n_vargs;
1288 rdata_array_alloc_element(array);
1289
1290 /* Read variadic arguments. */
1291
1292 idx = 0;
1293 while (rarg_n != NULL) {
1294 rarg = list_node_data(rarg_n, rdata_item_t *);
1295 assert(rarg->ic == ic_value);
1296
1297 run_value_item_to_var(rarg, &elem_var);
1298 array->element[idx] = elem_var;
1299
1300 rarg_n = list_next(arg_vals, rarg_n);
1301 idx += 1;
1302 }
1303
1304 var = rdata_var_new(vc_array);
1305 var->u.array_v = array;
1306
1307 /* Create reference to the new array. */
1308 ref_var = rdata_var_new(vc_ref);
1309 ref = rdata_ref_new();
1310 ref_var->u.ref_v = ref;
1311 ref->vref = var;
1312
1313 /* Declare variable using name of formal argument. */
1314 intmap_set(&block_ar->vars, varg->name->sid,
1315 ref_var);
1316 }
1317
1318 /* Check for excess real parameters. */
1319 if (rarg_n != NULL) {
1320 printf("Error: Too many arguments to '");
1321 symbol_print_fqn(outer_symbol);
1322 printf("'.\n");
1323 exit(1);
1324 }
1325}
1326
1327/** Fill setter argument in a procedure AR.
1328 *
1329 * When invoking a setter this is used to store its argument value in its
1330 * procedure activation record.
1331 *
1332 * @param run Runner object
1333 * @param proc_ar Existing procedure activation record where to store
1334 * the setter argument
1335 * @param arg_val Value items (rdata_item_t *) -- real argument value
1336 */
1337void run_proc_ar_set_setter_arg(run_t *run, run_proc_ar_t *proc_ar,
1338 rdata_item_t *arg_val)
1339{
1340 stree_prop_t *prop;
1341 run_block_ar_t *block_ar;
1342 list_node_t *block_ar_n;
1343 rdata_var_t *var;
1344
1345 (void) run;
1346
1347 /* AR should have been created with run_proc_ar_create(). */
1348 assert(proc_ar->proc != NULL);
1349
1350 /* The procedure being activated should belong to a property setter. */
1351 prop = symbol_to_prop(proc_ar->proc->outer_symbol);
1352 assert(prop != NULL);
1353 assert(proc_ar->proc == prop->setter);
1354
1355 /* Fetch first block activation record. */
1356 block_ar_n = list_first(&proc_ar->block_ar);
1357 assert(block_ar_n != NULL);
1358 block_ar = list_node_data(block_ar_n, run_block_ar_t *);
1359
1360 assert(arg_val->ic == ic_value);
1361
1362 /* Construct a variable from the argument value. */
1363 run_value_item_to_var(arg_val, &var);
1364
1365 /* Declare variable using name of formal argument. */
1366 intmap_set(&block_ar->vars, prop->setter_arg->name->sid, var);
1367}
1368
1369/** Print function activation backtrace.
1370 *
1371 * Prints a backtrace of activated functions for debugging purposes.
1372 *
1373 * @param run Runner object
1374 */
1375void run_print_fun_bt(run_t *run)
1376{
1377 list_node_t *node;
1378 run_proc_ar_t *proc_ar;
1379
1380 printf("Backtrace:\n");
1381 node = list_last(&run->thread_ar->proc_ar);
1382 while (node != NULL) {
1383 printf(" * ");
1384 proc_ar = list_node_data(node, run_proc_ar_t *);
1385 symbol_print_fqn(proc_ar->proc->outer_symbol);
1386 printf("\n");
1387
1388 node = list_prev(&run->thread_ar->proc_ar, node);
1389 }
1390}
1391
1392/** Destroy a block AR.
1393 *
1394 * @param run Runner object
1395 * @param proc_ar Pointer to block activation record
1396 */
1397void run_block_ar_destroy(run_t *run, run_block_ar_t *block_ar)
1398{
1399 map_elem_t *elem;
1400 rdata_var_t *var;
1401 int key;
1402
1403 (void) run;
1404
1405 elem = intmap_first(&block_ar->vars);
1406 while (elem != NULL) {
1407 /* Destroy the variable */
1408 var = intmap_elem_get_value(elem);
1409 rdata_var_destroy(var);
1410
1411 /* Remove the map element */
1412 key = intmap_elem_get_key(elem);
1413 intmap_set(&block_ar->vars, key, NULL);
1414
1415 elem = intmap_first(&block_ar->vars);
1416 }
1417
1418 intmap_fini(&block_ar->vars);
1419 run_block_ar_delete(block_ar);
1420}
1421
1422/** Convert item to value item.
1423 *
1424 * If @a item is a value, we just return a copy. If @a item is an address,
1425 * we read from the address.
1426 *
1427 * @param run Runner object
1428 * @param item Input item (value or address)
1429 * @param ritem Place to store pointer to new value item
1430 */
1431void run_cvt_value_item(run_t *run, rdata_item_t *item, rdata_item_t **ritem)
1432{
1433 rdata_value_t *value;
1434
1435 /*
1436 * This can happen when trying to use output of a function which
1437 * does not return a value.
1438 */
1439 if (item == NULL) {
1440 printf("Error: Sub-expression has no value.\n");
1441 exit(1);
1442 }
1443
1444 /* Address item. Perform read operation. */
1445 if (item->ic == ic_address) {
1446 run_address_read(run, item->u.address, ritem);
1447 return;
1448 }
1449
1450 /* Make a copy of the var node within. */
1451 value = rdata_value_new();
1452 rdata_var_copy(item->u.value->var, &value->var);
1453 *ritem = rdata_item_new(ic_value);
1454 (*ritem)->u.value = value;
1455}
1456
1457/** Get item var-class.
1458 *
1459 * Get var-class of @a item, regardless whether it is a value or address.
1460 * (I.e. the var class of the value or variable at the given address).
1461 *
1462 * @param run Runner object
1463 * @param item Value or address item
1464 * @return Varclass of @a item
1465 */
1466var_class_t run_item_get_vc(run_t *run, rdata_item_t *item)
1467{
1468 var_class_t vc;
1469 rdata_var_t *tpos;
1470
1471 (void) run;
1472
1473 switch (item->ic) {
1474 case ic_value:
1475 vc = item->u.value->var->vc;
1476 break;
1477 case ic_address:
1478 switch (item->u.address->ac) {
1479 case ac_var:
1480 vc = item->u.address->u.var_a->vref->vc;
1481 break;
1482 case ac_prop:
1483 /* Prefetch the value of the property. */
1484 tpos = run_aprop_get_tpos(run, item->u.address);
1485 vc = tpos->vc;
1486 break;
1487 default:
1488 assert(b_false);
1489 }
1490 break;
1491 default:
1492 assert(b_false);
1493 }
1494
1495 return vc;
1496}
1497
1498/** Get pointer to current var node in temporary copy in property address.
1499 *
1500 * A property address refers to a specific @c var node in a property.
1501 * This function will fetch a copy of the property value (by running
1502 * its getter) if there is not a temporary copy in the address yet.
1503 * It returns a pointer to the relevant @c var node in the temporary
1504 * copy.
1505 *
1506 * @param run Runner object
1507 * @param addr Address of class @c ac_prop
1508 * @return Pointer to var node
1509 */
1510static rdata_var_t *run_aprop_get_tpos(run_t *run, rdata_address_t *addr)
1511{
1512 rdata_item_t *ritem;
1513
1514 assert(addr->ac == ac_prop);
1515
1516 if (addr->u.prop_a->tvalue == NULL) {
1517 /* Fetch value of the property. */
1518 run_address_read(run, addr, &ritem);
1519 assert(ritem->ic == ic_value);
1520 addr->u.prop_a->tvalue = ritem->u.value;
1521 addr->u.prop_a->tpos = addr->u.prop_a->tvalue->var;
1522 }
1523
1524 return addr->u.prop_a->tpos;
1525}
1526
1527/** Read data from an address.
1528 *
1529 * Read value from the specified address.
1530 *
1531 * @param run Runner object
1532 * @param address Address to read
1533 * @param ritem Place to store pointer to the value that was read
1534 */
1535void run_address_read(run_t *run, rdata_address_t *address,
1536 rdata_item_t **ritem)
1537{
1538 (void) run;
1539 assert(ritem != NULL);
1540
1541 switch (address->ac) {
1542 case ac_var:
1543 rdata_var_read(address->u.var_a->vref, ritem);
1544 break;
1545 case ac_prop:
1546 run_aprop_read(run, address->u.prop_a, ritem);
1547 break;
1548 }
1549
1550 assert(*ritem == NULL || (*ritem)->ic == ic_value);
1551}
1552
1553/** Write data to an address.
1554 *
1555 * Store value @a value at address @a address.
1556 *
1557 * @param run Runner object
1558 * @param address Address to write
1559 * @param value Value to store at the address
1560 */
1561void run_address_write(run_t *run, rdata_address_t *address,
1562 rdata_value_t *value)
1563{
1564 (void) run;
1565
1566 switch (address->ac) {
1567 case ac_var:
1568 rdata_var_write(address->u.var_a->vref, value);
1569 break;
1570 case ac_prop:
1571 run_aprop_write(run, address->u.prop_a, value);
1572 break;
1573 }
1574}
1575
1576/** Read data from a property address.
1577 *
1578 * This involves invoking the property getter procedure.
1579 *
1580 * @param run Runner object.
1581 * @param addr_prop Property address to read.
1582 * @param ritem Place to store pointer to the value that was read.
1583 */
1584static void run_aprop_read(run_t *run, rdata_addr_prop_t *addr_prop,
1585 rdata_item_t **ritem)
1586{
1587 rdata_deleg_t *deleg;
1588 rdata_var_t *obj;
1589 stree_symbol_t *prop_sym;
1590 stree_prop_t *prop;
1591
1592 run_proc_ar_t *proc_ar;
1593
1594 rdata_var_t *cvar;
1595
1596#ifdef DEBUG_RUN_TRACE
1597 printf("Read from property.\n");
1598#endif
1599 /*
1600 * If @c tvalue is present, we need to use the relevant part from that
1601 * instead of re-reading the whole thing.
1602 */
1603 if (addr_prop->tvalue != NULL) {
1604 /* Copy the value */
1605 rdata_var_copy(addr_prop->tpos, &cvar);
1606 *ritem = rdata_item_new(ic_value);
1607 (*ritem)->u.value = rdata_value_new();
1608 (*ritem)->u.value->var = cvar;
1609 return;
1610 }
1611
1612 if (addr_prop->apc == apc_named)
1613 deleg = addr_prop->u.named->prop_d;
1614 else
1615 deleg = addr_prop->u.indexed->object_d;
1616
1617 obj = deleg->obj;
1618 prop_sym = deleg->sym;
1619 prop = symbol_to_prop(prop_sym);
1620 assert(prop != NULL);
1621
1622 if (prop->getter == NULL) {
1623 printf("Error: Property is not readable.\n");
1624 exit(1);
1625 }
1626
1627 /* Create procedure activation record. */
1628 run_proc_ar_create(run, obj, prop->getter, &proc_ar);
1629
1630 /* Fill in arguments (indices). */
1631 if (addr_prop->apc == apc_indexed) {
1632 run_proc_ar_set_args(run, proc_ar,
1633 &addr_prop->u.indexed->args);
1634 }
1635
1636 /* Run getter. */
1637 run_proc(run, proc_ar, ritem);
1638
1639 /* Destroy procedure activation record. */
1640 run_proc_ar_destroy(run, proc_ar);
1641
1642#ifdef DEBUG_RUN_TRACE
1643 printf("Getter returns ");
1644 rdata_item_print(*ritem);
1645 printf(".\n");
1646 printf("Done reading from property.\n");
1647#endif
1648}
1649
1650/** Write data to a property address.
1651 *
1652 * This involves invoking the property setter procedure.
1653 *
1654 * @param run Runner object
1655 * @param addr_prop Property address to write
1656 * @param value Value to store at the address
1657 */
1658static void run_aprop_write(run_t *run, rdata_addr_prop_t *addr_prop,
1659 rdata_value_t *value)
1660{
1661 rdata_deleg_t *deleg;
1662 rdata_var_t *obj;
1663 stree_symbol_t *prop_sym;
1664 stree_prop_t *prop;
1665
1666 run_proc_ar_t *proc_ar;
1667 rdata_item_t *vitem;
1668 rdata_item_t *ritem;
1669
1670#ifdef DEBUG_RUN_TRACE
1671 printf("Write to property.\n");
1672#endif
1673 /* If @c tvalue is present, we need to modify it and write it back. */
1674 if (addr_prop->tvalue != NULL) {
1675 printf("Unimplemented: Read-modify-write property access.\n");
1676 exit(1);
1677 }
1678
1679 if (addr_prop->apc == apc_named)
1680 deleg = addr_prop->u.named->prop_d;
1681 else
1682 deleg = addr_prop->u.indexed->object_d;
1683
1684 obj = deleg->obj;
1685 prop_sym = deleg->sym;
1686 prop = symbol_to_prop(prop_sym);
1687 assert(prop != NULL);
1688
1689 if (prop->setter == NULL) {
1690 printf("Error: Property is not writable.\n");
1691 exit(1);
1692 }
1693
1694 vitem = rdata_item_new(ic_value);
1695 vitem->u.value = value;
1696
1697 /* Create procedure activation record. */
1698 run_proc_ar_create(run, obj, prop->setter, &proc_ar);
1699
1700 /* Fill in arguments (indices). */
1701 if (addr_prop->apc == apc_indexed) {
1702 run_proc_ar_set_args(run, proc_ar,
1703 &addr_prop->u.indexed->args);
1704 }
1705
1706 /* Fill in value argument for setter. */
1707 run_proc_ar_set_setter_arg(run, proc_ar, vitem);
1708
1709 /* Run setter. */
1710 run_proc(run, proc_ar, &ritem);
1711
1712 /* Setter should not return a value. */
1713 assert(ritem == NULL);
1714
1715 /* Destroy procedure activation record. */
1716 run_proc_ar_destroy(run, proc_ar);
1717
1718#ifdef DEBUG_RUN_TRACE
1719 printf("Done writing to property.\n");
1720#endif
1721}
1722
1723/** Return reference to a variable.
1724 *
1725 * Constructs a reference (value item) pointing to @a var.
1726 *
1727 * @param run Runner object
1728 * @param var Variable node that is being referenced
1729 * @param res Place to store pointer to new reference.
1730 */
1731void run_reference(run_t *run, rdata_var_t *var, rdata_item_t **res)
1732{
1733 rdata_ref_t *ref;
1734 rdata_var_t *ref_var;
1735 rdata_value_t *ref_value;
1736 rdata_item_t *ref_item;
1737
1738 (void) run;
1739
1740 /* Create reference to the variable. */
1741 ref = rdata_ref_new();
1742 ref_var = rdata_var_new(vc_ref);
1743 ref->vref = var;
1744 ref_var->u.ref_v = ref;
1745
1746 /* Construct value of the reference to return. */
1747 ref_item = rdata_item_new(ic_value);
1748 ref_value = rdata_value_new();
1749 ref_item->u.value = ref_value;
1750 ref_value->var = ref_var;
1751
1752 *res = ref_item;
1753}
1754
1755/** Return address of reference target.
1756 *
1757 * Takes a reference (address or value) and returns the address (item) of
1758 * the target of the reference.
1759 *
1760 * @param run Runner object
1761 * @param ref Reference
1762 * @param cspan Cspan to put into exception if reference is nil
1763 * or @c NULL if no cspan is provided.
1764 * @param rtitem Place to store pointer to the resulting address.
1765 */
1766void run_dereference(run_t *run, rdata_item_t *ref, cspan_t *cspan,
1767 rdata_item_t **ritem)
1768{
1769 rdata_item_t *ref_val;
1770 rdata_item_t *item;
1771 rdata_address_t *address;
1772 rdata_addr_var_t *addr_var;
1773
1774#ifdef DEBUG_RUN_TRACE
1775 printf("run_dereference()\n");
1776#endif
1777 run_cvt_value_item(run, ref, &ref_val);
1778 if (run_is_bo(run)) {
1779 *ritem = run_recovery_item(run);
1780 return;
1781 }
1782
1783 assert(ref_val->u.value->var->vc == vc_ref);
1784
1785 item = rdata_item_new(ic_address);
1786 address = rdata_address_new(ac_var);
1787 addr_var = rdata_addr_var_new();
1788 item->u.address = address;
1789 address->u.var_a = addr_var;
1790 addr_var->vref = ref_val->u.value->var->u.ref_v->vref;
1791
1792 rdata_item_destroy(ref_val);
1793
1794 if (addr_var->vref == NULL) {
1795#ifdef DEBUG_RUN_TRACE
1796 printf("Error: Accessing null reference.\n");
1797#endif
1798 /* Raise Error.NilReference */
1799 run_raise_exc(run, run->program->builtin->error_nilreference,
1800 cspan);
1801 *ritem = run_recovery_item(run);
1802 return;
1803 }
1804
1805#ifdef DEBUG_RUN_TRACE
1806 printf("vref set to %p\n", addr_var->vref);
1807#endif
1808 *ritem = item;
1809}
1810
1811/** Raise an exception of the given class.
1812 *
1813 * Used when the interpreter generates an exception due to a run-time
1814 * error (not for the @c raise statement).
1815 *
1816 * @param run Runner object
1817 * @param csi Exception class
1818 * @param cspan Cspan of code that caused exception (for debugging)
1819 */
1820void run_raise_exc(run_t *run, stree_csi_t *csi, cspan_t *cspan)
1821{
1822 rdata_item_t *exc_vi;
1823
1824 /* Store exception cspan in thread AR. */
1825 run->thread_ar->exc_cspan = cspan;
1826
1827 /* Create exception object. */
1828 run_new_csi_inst_ref(run, csi, sn_nonstatic, &exc_vi);
1829 assert(exc_vi->ic == ic_value);
1830
1831 /* Store exception object in thread AR. */
1832 run->thread_ar->exc_payload = exc_vi->u.value;
1833
1834 /* Start exception bailout. */
1835 run->thread_ar->bo_mode = bm_exc;
1836}
1837
1838/** Determine if we are bailing out.
1839 *
1840 * @param run Runner object
1841 * @return @c b_true if we are bailing out, @c b_false otherwise
1842 */
1843bool_t run_is_bo(run_t *run)
1844{
1845 return run->thread_ar->bo_mode != bm_none;
1846}
1847
1848/** Construct a new variable of the given type.
1849 *
1850 * The variable is allocated and initialized with a default value
1851 * based on type item @a ti. For reference types the default value
1852 * is a null reference. At this point this does not work for generic
1853 * types (we need RTTI).
1854 *
1855 * @param run Runner object
1856 * @param ti Type of variable to create (type item)
1857 * @param rvar Place to store pointer to new variable
1858 */
1859void run_var_new(run_t *run, tdata_item_t *ti, rdata_var_t **rvar)
1860{
1861 rdata_var_t *var;
1862
1863 switch (ti->tic) {
1864 case tic_tprimitive:
1865 run_var_new_tprimitive(run, ti->u.tprimitive, rvar);
1866 break;
1867 case tic_tobject:
1868 case tic_tarray:
1869 run_var_new_null_ref(run, rvar);
1870 break;
1871 case tic_tdeleg:
1872 run_var_new_deleg(run, rvar);
1873 break;
1874 case tic_tebase:
1875 /*
1876 * One cannot declare variable of ebase type. It is just
1877 * type of expressions referring to enum types.
1878 */
1879 assert(b_false);
1880 /* Fallthrough */
1881 case tic_tenum:
1882 run_var_new_enum(run, ti->u.tenum, rvar);
1883 break;
1884 case tic_tfun:
1885 run_var_new_deleg(run, rvar);
1886 break;
1887 case tic_tvref:
1888 /*
1889 * XXX Need to obtain run-time value of type argument to
1890 * initialize variable properly.
1891 */
1892 var = rdata_var_new(vc_int);
1893 var->u.int_v = rdata_int_new();
1894 bigint_init(&var->u.int_v->value, 0);
1895 *rvar = var;
1896 break;
1897 case tic_ignore:
1898 assert(b_false);
1899 }
1900}
1901
1902/** Construct a new variable of primitive type.
1903 *
1904 * The variable is allocated and initialized with a default value
1905 * based on primitive type item @a tprimitive.
1906 *
1907 * @param run Runner object
1908 * @param ti Primitive type of variable to create
1909 * @param rvar Place to store pointer to new variable
1910 */
1911static void run_var_new_tprimitive(run_t *run, tdata_primitive_t *tprimitive,
1912 rdata_var_t **rvar)
1913{
1914 rdata_var_t *var;
1915
1916 (void) run;
1917
1918 /* Make compiler happy. */
1919 var = NULL;
1920
1921 switch (tprimitive->tpc) {
1922 case tpc_bool:
1923 var = rdata_var_new(vc_bool);
1924 var->u.bool_v = rdata_bool_new();
1925 var->u.bool_v->value = b_false;
1926 break;
1927 case tpc_char:
1928 var = rdata_var_new(vc_char);
1929 var->u.char_v = rdata_char_new();
1930 bigint_init(&var->u.char_v->value, 0);
1931 break;
1932 case tpc_int:
1933 var = rdata_var_new(vc_int);
1934 var->u.int_v = rdata_int_new();
1935 bigint_init(&var->u.int_v->value, 0);
1936 break;
1937 case tpc_nil:
1938 assert(b_false);
1939 /* Fallthrough */
1940 case tpc_string:
1941 var = rdata_var_new(vc_string);
1942 var->u.string_v = rdata_string_new();
1943 var->u.string_v->value = "";
1944 break;
1945 case tpc_resource:
1946 var = rdata_var_new(vc_resource);
1947 var->u.resource_v = rdata_resource_new();
1948 var->u.resource_v->data = NULL;
1949 break;
1950 }
1951
1952 *rvar = var;
1953}
1954
1955/** Construct a new variable containing null reference.
1956 *
1957 * @param run Runner object
1958 * @param rvar Place to store pointer to new variable
1959 */
1960static void run_var_new_null_ref(run_t *run, rdata_var_t **rvar)
1961{
1962 rdata_var_t *var;
1963
1964 (void) run;
1965
1966 /* Return null reference. */
1967 var = rdata_var_new(vc_ref);
1968 var->u.ref_v = rdata_ref_new();
1969
1970 *rvar = var;
1971}
1972
1973/** Construct a new variable containing invalid delegate.
1974 *
1975 * @param run Runner object
1976 * @param rvar Place to store pointer to new variable
1977 */
1978static void run_var_new_deleg(run_t *run, rdata_var_t **rvar)
1979{
1980 rdata_var_t *var;
1981
1982 (void) run;
1983
1984 /* Return null reference. */
1985 var = rdata_var_new(vc_deleg);
1986 var->u.deleg_v = rdata_deleg_new();
1987
1988 *rvar = var;
1989}
1990
1991/** Construct a new variable containing default value of an enum type.
1992 *
1993 * @param run Runner object
1994 * @param rvar Place to store pointer to new variable
1995 */
1996static void run_var_new_enum(run_t *run, tdata_enum_t *tenum,
1997 rdata_var_t **rvar)
1998{
1999 rdata_var_t *var;
2000 list_node_t *embr_n;
2001 stree_embr_t *embr;
2002
2003 (void) run;
2004
2005 /* Get first member of enum which will serve as default value. */
2006 embr_n = list_first(&tenum->enum_d->members);
2007 assert(embr_n != NULL);
2008
2009 embr = list_node_data(embr_n, stree_embr_t *);
2010
2011 /* Return null reference. */
2012 var = rdata_var_new(vc_enum);
2013 var->u.enum_v = rdata_enum_new();
2014 var->u.enum_v->value = embr;
2015
2016 *rvar = var;
2017}
2018
2019/** Construct a new thread activation record.
2020 *
2021 * @param run Runner object
2022 * @return New thread AR.
2023 */
2024run_thread_ar_t *run_thread_ar_new(void)
2025{
2026 run_thread_ar_t *thread_ar;
2027
2028 thread_ar = calloc(1, sizeof(run_thread_ar_t));
2029 if (thread_ar == NULL) {
2030 printf("Memory allocation failed.\n");
2031 exit(1);
2032 }
2033
2034 return thread_ar;
2035}
2036
2037/** Allocate a new procedure activation record.
2038 *
2039 * @return New procedure AR.
2040 */
2041run_proc_ar_t *run_proc_ar_new(void)
2042{
2043 run_proc_ar_t *proc_ar;
2044
2045 proc_ar = calloc(1, sizeof(run_proc_ar_t));
2046 if (proc_ar == NULL) {
2047 printf("Memory allocation failed.\n");
2048 exit(1);
2049 }
2050
2051 return proc_ar;
2052}
2053
2054/** Deallocate a procedure activation record.
2055 *
2056 * @return New procedure AR.
2057 */
2058void run_proc_ar_delete(run_proc_ar_t *proc_ar)
2059{
2060 assert(proc_ar != NULL);
2061 free(proc_ar);
2062}
2063
2064/** Allocate a new block activation record.
2065 *
2066 * @param run Runner object
2067 * @return New block AR.
2068 */
2069run_block_ar_t *run_block_ar_new(void)
2070{
2071 run_block_ar_t *block_ar;
2072
2073 block_ar = calloc(1, sizeof(run_block_ar_t));
2074 if (block_ar == NULL) {
2075 printf("Memory allocation failed.\n");
2076 exit(1);
2077 }
2078
2079 return block_ar;
2080}
2081
2082/** Deallocate a new block activation record.
2083 *
2084 * @param run Runner object
2085 * @return New block AR.
2086 */
2087void run_block_ar_delete(run_block_ar_t *block_ar)
2088{
2089 assert(block_ar != NULL);
2090 free(block_ar);
2091}
Note: See TracBrowser for help on using the repository browser.