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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c5ad226 was c5cb943d, checked in by Jiri Svoboda <jiri@…>, 15 years ago

Update SBI to rev. 291.

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