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

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

Update SBI to rev. 157.

  • Property mode set to 100644
File size: 29.2 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 "builtin.h"
35#include "debug.h"
36#include "intmap.h"
37#include "list.h"
38#include "mytypes.h"
39#include "rdata.h"
40#include "run_expr.h"
41#include "run_texpr.h"
42#include "stree.h"
43#include "strtab.h"
44#include "symbol.h"
45#include "tdata.h"
46
47#include "run.h"
48
49static void run_block(run_t *run, stree_block_t *block);
50static void run_exps(run_t *run, stree_exps_t *exps, rdata_item_t **res);
51static void run_vdecl(run_t *run, stree_vdecl_t *vdecl);
52static void run_if(run_t *run, stree_if_t *if_s);
53static void run_while(run_t *run, stree_while_t *while_s);
54static void run_raise(run_t *run, stree_raise_t *raise_s);
55static void run_return(run_t *run, stree_return_t *return_s);
56static void run_wef(run_t *run, stree_wef_t *wef_s);
57
58static bool_t run_exc_match(run_t *run, stree_except_t *except_c);
59static rdata_var_t *run_aprop_get_tpos(run_t *run, rdata_address_t *aprop);
60
61static void run_aprop_read(run_t *run, rdata_addr_prop_t *addr_prop,
62 rdata_item_t **ritem);
63static void run_aprop_write(run_t *run, rdata_addr_prop_t *addr_prop,
64 rdata_value_t *value);
65
66/** Initialize runner instance. */
67void run_init(run_t *run)
68{
69 (void) run;
70}
71
72/** Run program */
73void run_program(run_t *run, stree_program_t *prog)
74{
75 stree_symbol_t *main_fun_sym;
76 stree_fun_t *main_fun;
77 stree_ident_t *fake_ident;
78 list_t main_args;
79 run_proc_ar_t *proc_ar;
80 rdata_item_t *res;
81
82 /* Note down link to program code. */
83 run->program = prog;
84
85 /* Initialize thread activation record. */
86 run->thread_ar = run_thread_ar_new();
87 list_init(&run->thread_ar->proc_ar);
88 run->thread_ar->bo_mode = bm_none;
89
90 /*
91 * Find entry point @c Main().
92 */
93 fake_ident = stree_ident_new();
94 fake_ident->sid = strtab_get_sid("Main");
95 main_fun_sym = symbol_find_epoint(prog, fake_ident);
96 if (main_fun_sym == NULL) {
97 printf("Error: Entry point 'Main' not found.\n");
98 exit(1);
99 }
100
101 main_fun = symbol_to_fun(main_fun_sym);
102 assert(main_fun != NULL);
103
104#ifdef DEBUG_RUN_TRACE
105 printf("Found function '"); symbol_print_fqn(main_fun_sym);
106 printf("'.\n");
107#endif
108
109 /* Run function @c main. */
110 list_init(&main_args);
111 run_proc_ar_create(run, NULL, main_fun->proc, &proc_ar);
112 run_proc_ar_set_args(run, proc_ar, &main_args);
113 run_proc(run, proc_ar, &res);
114
115 /* Check for unhandled exceptions. */
116 if (run->thread_ar->bo_mode != bm_none) {
117 assert(run->thread_ar->bo_mode == bm_exc);
118 printf("Error: Unhandled exception.\n");
119 exit(1);
120 }
121}
122
123/** Run procedure. */
124void run_proc(run_t *run, run_proc_ar_t *proc_ar, rdata_item_t **res)
125{
126 stree_proc_t *proc;
127 list_node_t *node;
128
129 proc = proc_ar->proc;
130
131#ifdef DEBUG_RUN_TRACE
132 printf("Start executing function '");
133 symbol_print_fqn(proc->outer_symbol);
134 printf("'.\n");
135#endif
136 /* Add procedure AR to the stack. */
137 list_append(&run->thread_ar->proc_ar, proc_ar);
138
139 /* Run main procedure block. */
140 if (proc->body != NULL) {
141 run_block(run, proc->body);
142 } else {
143 builtin_run_proc(run, proc);
144 }
145
146 /* Handle bailout. */
147 switch (run->thread_ar->bo_mode) {
148 case bm_stat:
149 printf("Error: Misplaced 'break' statement.\n");
150 exit(1);
151 case bm_proc:
152 run->thread_ar->bo_mode = bm_none;
153 break;
154 default:
155 break;
156 }
157
158#ifdef DEBUG_RUN_TRACE
159 printf("Done executing procedure '");
160 symbol_print_fqn(proc->outer_symbol);
161 printf("'.\n");
162
163 run_print_fun_bt(run);
164#endif
165 /* Remove procedure activation record from the stack. */
166 node = list_last(&run->thread_ar->proc_ar);
167 assert(list_node_data(node, run_proc_ar_t *) == proc_ar);
168 list_remove(&run->thread_ar->proc_ar, node);
169
170 /* Procedure should not return an address. */
171 assert(proc_ar->retval == NULL || proc_ar->retval->ic == ic_value);
172 *res = proc_ar->retval;
173}
174
175/** Run code block */
176static void run_block(run_t *run, stree_block_t *block)
177{
178 run_proc_ar_t *proc_ar;
179 run_block_ar_t *block_ar;
180 list_node_t *node;
181 stree_stat_t *stat;
182
183#ifdef DEBUG_RUN_TRACE
184 printf("Executing one code block.\n");
185#endif
186
187 /* Create block activation record. */
188 block_ar = run_block_ar_new();
189 intmap_init(&block_ar->vars);
190
191 /* Add block activation record to the stack. */
192 proc_ar = run_get_current_proc_ar(run);
193 list_append(&proc_ar->block_ar, block_ar);
194
195 node = list_first(&block->stats);
196 while (node != NULL) {
197 stat = list_node_data(node, stree_stat_t *);
198 run_stat(run, stat, NULL);
199
200 if (run->thread_ar->bo_mode != bm_none)
201 break;
202
203 node = list_next(&block->stats, node);
204 }
205
206#ifdef DEBUG_RUN_TRACE
207 printf("Done executing code block.\n");
208#endif
209
210 /* Remove block activation record from the stack. */
211 node = list_last(&proc_ar->block_ar);
212 assert(list_node_data(node, run_block_ar_t *) == block_ar);
213 list_remove(&proc_ar->block_ar, node);
214}
215
216/** Run statement.
217 *
218 * Executes a statement. If @a res is not NULL and the statement is an
219 * expression statement with a value, the value item will be stored to
220 * @a res.
221 *
222 * @param run Runner object.
223 * @param stat Statement to run.
224 * @param res Place to store exps result or NULL if not interested.
225 */
226void run_stat(run_t *run, stree_stat_t *stat, rdata_item_t **res)
227{
228#ifdef DEBUG_RUN_TRACE
229 printf("Executing one statement %p.\n", stat);
230#endif
231
232 if (res != NULL)
233 *res = NULL;
234
235 switch (stat->sc) {
236 case st_exps:
237 run_exps(run, stat->u.exp_s, res);
238 break;
239 case st_vdecl:
240 run_vdecl(run, stat->u.vdecl_s);
241 break;
242 case st_if:
243 run_if(run, stat->u.if_s);
244 break;
245 case st_while:
246 run_while(run, stat->u.while_s);
247 break;
248 case st_raise:
249 run_raise(run, stat->u.raise_s);
250 break;
251 case st_return:
252 run_return(run, stat->u.return_s);
253 break;
254 case st_wef:
255 run_wef(run, stat->u.wef_s);
256 break;
257 case st_for:
258 printf("Ignoring unimplemented statement type %d.\n", stat->sc);
259 break;
260 default:
261 assert(b_false);
262 }
263}
264
265/** Run expression statement.
266 *
267 * Executes an expression statement. If @a res is not NULL then the value
268 * of the expression (or NULL if it has no value) will be stored to @a res.
269 *
270 * @param run Runner object.
271 * @param exps Expression statement to run.
272 * @param res Place to store exps result or NULL if not interested.
273 */
274static void run_exps(run_t *run, stree_exps_t *exps, rdata_item_t **res)
275{
276 rdata_item_t *rexpr;
277
278#ifdef DEBUG_RUN_TRACE
279 printf("Executing expression statement.\n");
280#endif
281 run_expr(run, exps->expr, &rexpr);
282
283 if (res != NULL)
284 *res = rexpr;
285}
286
287/** Run variable declaration statement. */
288static void run_vdecl(run_t *run, stree_vdecl_t *vdecl)
289{
290 run_block_ar_t *block_ar;
291 rdata_var_t *var, *old_var;
292 rdata_int_t *int_v;
293
294#ifdef DEBUG_RUN_TRACE
295 printf("Executing variable declaration statement.\n");
296#endif
297
298 /* XXX Need to support other variables than int. */
299
300 var = rdata_var_new(vc_int);
301 int_v = rdata_int_new();
302
303 var->u.int_v = int_v;
304 int_v->value = 0;
305
306 block_ar = run_get_current_block_ar(run);
307 old_var = (rdata_var_t *) intmap_get(&block_ar->vars, vdecl->name->sid);
308
309 if (old_var != NULL) {
310 printf("Error: Duplicate variable '%s'\n",
311 strtab_get_str(vdecl->name->sid));
312 exit(1);
313 }
314
315 intmap_set(&block_ar->vars, vdecl->name->sid, var);
316
317#ifdef DEBUG_RUN_TRACE
318 printf("Declared variable '%s'\n", strtab_get_str(vdecl->name->sid));
319#endif
320}
321
322/** Run @c if statement. */
323static void run_if(run_t *run, stree_if_t *if_s)
324{
325 rdata_item_t *rcond;
326
327#ifdef DEBUG_RUN_TRACE
328 printf("Executing if statement.\n");
329#endif
330 run_expr(run, if_s->cond, &rcond);
331
332 if (run_item_boolean_value(run, rcond) == b_true) {
333#ifdef DEBUG_RUN_TRACE
334 printf("Taking true path.\n");
335#endif
336 run_block(run, if_s->if_block);
337 } else {
338#ifdef DEBUG_RUN_TRACE
339 printf("Taking false path.\n");
340#endif
341 if (if_s->else_block != NULL)
342 run_block(run, if_s->else_block);
343 }
344
345#ifdef DEBUG_RUN_TRACE
346 printf("If statement terminated.\n");
347#endif
348}
349
350/** Run @c while statement. */
351static void run_while(run_t *run, stree_while_t *while_s)
352{
353 rdata_item_t *rcond;
354
355#ifdef DEBUG_RUN_TRACE
356 printf("Executing while statement.\n");
357#endif
358 run_expr(run, while_s->cond, &rcond);
359
360 while (run_item_boolean_value(run, rcond) == b_true) {
361 run_block(run, while_s->body);
362 run_expr(run, while_s->cond, &rcond);
363
364 if (run->thread_ar->bo_mode != bm_none)
365 break;
366 }
367
368#ifdef DEBUG_RUN_TRACE
369 printf("While statement terminated.\n");
370#endif
371}
372
373/** Run @c raise statement. */
374static void run_raise(run_t *run, stree_raise_t *raise_s)
375{
376 rdata_item_t *rexpr;
377 rdata_item_t *rexpr_vi;
378
379#ifdef DEBUG_RUN_TRACE
380 printf("Executing raise statement.\n");
381#endif
382 run_expr(run, raise_s->expr, &rexpr);
383 run_cvt_value_item(run, rexpr, &rexpr_vi);
384
385 /* Store expression result in thread AR. */
386 run->thread_ar->exc_payload = rexpr_vi->u.value;
387
388 /* Start exception bailout. */
389 run->thread_ar->bo_mode = bm_exc;
390}
391
392/** Run @c return statement. */
393static void run_return(run_t *run, stree_return_t *return_s)
394{
395 rdata_item_t *rexpr;
396 rdata_item_t *rexpr_vi;
397 run_proc_ar_t *proc_ar;
398
399#ifdef DEBUG_RUN_TRACE
400 printf("Executing return statement.\n");
401#endif
402 run_expr(run, return_s->expr, &rexpr);
403 run_cvt_value_item(run, rexpr, &rexpr_vi);
404
405 /* Store expression result in function AR. */
406 proc_ar = run_get_current_proc_ar(run);
407 proc_ar->retval = rexpr_vi;
408
409 /* Force control to ascend and leave the procedure. */
410 if (run->thread_ar->bo_mode == bm_none)
411 run->thread_ar->bo_mode = bm_proc;
412}
413
414/** Run @c with-except-finally statement. */
415static void run_wef(run_t *run, stree_wef_t *wef_s)
416{
417 list_node_t *except_n;
418 stree_except_t *except_c;
419 rdata_value_t *exc_payload;
420 run_bailout_mode_t bo_mode;
421
422#ifdef DEBUG_RUN_TRACE
423 printf("Executing with-except-finally statement.\n");
424#endif
425 run_block(run, wef_s->with_block);
426
427 if (run->thread_ar->bo_mode == bm_exc) {
428#ifdef DEBUG_RUN_TRACE
429 printf("With statement detected exception.\n");
430#endif
431 /* Reset to normal execution. */
432 run->thread_ar->bo_mode = bm_none;
433
434 /* Look for an except block. */
435 except_n = list_first(&wef_s->except_clauses);
436 while (except_n != NULL) {
437 except_c = list_node_data(except_n, stree_except_t *);
438 if (run_exc_match(run, except_c))
439 break;
440
441 except_n = list_next(&wef_s->except_clauses, except_n);
442 }
443
444 /* If one was found, execute it. */
445 if (except_n != NULL)
446 run_block(run, except_c->block);
447
448 /* Execute finally block */
449 if (wef_s->finally_block != NULL) {
450 /* Put exception on the side temporarily. */
451 bo_mode = run->thread_ar->bo_mode;
452 exc_payload = run->thread_ar->exc_payload;
453
454 run->thread_ar->bo_mode = bm_none;
455 run->thread_ar->exc_payload = NULL;
456
457 run_block(run, wef_s->finally_block);
458
459 if (bo_mode == bm_exc) {
460 /*
461 * Restore the original exception. If another
462 * exception occured in the finally block (i.e.
463 * double fault), it is forgotten.
464 */
465 run->thread_ar->bo_mode = bm_exc;
466 run->thread_ar->exc_payload = exc_payload;
467 }
468 }
469 }
470
471#ifdef DEBUG_RUN_TRACE
472 printf("With-except-finally statement terminated.\n");
473#endif
474}
475
476/** Determine whether currently active exception matches @c except clause.
477 *
478 * Checks if the currently active exception in the runner object @c run
479 * matches except clause @c except_c. Generates an error if the exception
480 * payload has invalid type (i.e. not an object).
481 *
482 * @param run Runner object.
483 * @param except_c @c except clause.
484 * @return @c b_true if there is a match, @c b_false otherwise.
485 */
486static bool_t run_exc_match(run_t *run, stree_except_t *except_c)
487{
488 rdata_value_t *payload;
489 rdata_var_t *payload_v;
490 rdata_object_t *payload_o;
491 tdata_item_t *etype;
492
493 payload = run->thread_ar->exc_payload;
494 assert(payload != NULL);
495
496 if (payload->var->vc != vc_ref) {
497 printf("Error: Exception payload must be an object "
498 "(found type %d).\n", payload->var->vc);
499 exit(1);
500 }
501
502 payload_v = payload->var->u.ref_v->vref;
503 if (payload_v->vc != vc_object) {
504 printf("Error: Exception payload must be an object "
505 "(found type %d).\n", payload_v->vc);
506 exit(1);
507 }
508
509 payload_o = payload_v->u.object_v;
510
511#ifdef DEBUG_RUN_TRACE
512 printf("Active exception: '");
513 symbol_print_fqn(payload_o->class_sym);
514 printf("'.\n");
515#endif
516 assert(payload_o->class_sym != NULL);
517 assert(payload_o->class_sym->sc == sc_csi);
518
519 /* Evaluate type expression in except clause. */
520 run_texpr(run->program, run_get_current_csi(run), except_c->etype,
521 &etype);
522
523 return tdata_is_csi_derived_from_ti(payload_o->class_sym->u.csi,
524 etype);
525}
526
527/** Raise an irrecoverable run-time error, start bailing out.
528 *
529 * Raises an error that cannot be handled by the user program.
530 */
531void run_raise_error(run_t *run)
532{
533 run->thread_ar->bo_mode = bm_error;
534 run->thread_ar->error = b_true;
535}
536
537/** Construct a special recovery item. */
538rdata_item_t *run_recovery_item(run_t *run)
539{
540 (void) run;
541 return NULL;
542}
543
544/** Find a local variable in the currently active function. */
545rdata_var_t *run_local_vars_lookup(run_t *run, sid_t name)
546{
547 run_proc_ar_t *proc_ar;
548 run_block_ar_t *block_ar;
549 rdata_var_t *var;
550 list_node_t *node;
551
552 proc_ar = run_get_current_proc_ar(run);
553 node = list_last(&proc_ar->block_ar);
554
555 /* Walk through all block activation records. */
556 while (node != NULL) {
557 block_ar = list_node_data(node, run_block_ar_t *);
558 var = intmap_get(&block_ar->vars, name);
559 if (var != NULL)
560 return var;
561
562 node = list_prev(&proc_ar->block_ar, node);
563 }
564
565 /* No match */
566 return NULL;
567}
568
569/** Get current function activation record. */
570run_proc_ar_t *run_get_current_proc_ar(run_t *run)
571{
572 list_node_t *node;
573
574 node = list_last(&run->thread_ar->proc_ar);
575 return list_node_data(node, run_proc_ar_t *);
576}
577
578/** Get current block activation record. */
579run_block_ar_t *run_get_current_block_ar(run_t *run)
580{
581 run_proc_ar_t *proc_ar;
582 list_node_t *node;
583
584 proc_ar = run_get_current_proc_ar(run);
585
586 node = list_last(&proc_ar->block_ar);
587 return list_node_data(node, run_block_ar_t *);
588}
589
590/** Get current CSI. */
591stree_csi_t *run_get_current_csi(run_t *run)
592{
593 run_proc_ar_t *proc_ar;
594
595 proc_ar = run_get_current_proc_ar(run);
596 return proc_ar->proc->outer_symbol->outer_csi;
597}
598
599/** Construct variable from a value item.
600 *
601 * XXX This should be in fact implemented using existing code as:
602 *
603 * (1) Create a variable of the desired type.
604 * (2) Initialize the variable with the provided value.
605 */
606void run_value_item_to_var(rdata_item_t *item, rdata_var_t **var)
607{
608 rdata_int_t *int_v;
609 rdata_string_t *string_v;
610 rdata_ref_t *ref_v;
611 rdata_var_t *in_var;
612
613 assert(item->ic == ic_value);
614 in_var = item->u.value->var;
615
616 switch (in_var->vc) {
617 case vc_int:
618 *var = rdata_var_new(vc_int);
619 int_v = rdata_int_new();
620
621 (*var)->u.int_v = int_v;
622 int_v->value = item->u.value->var->u.int_v->value;
623 break;
624 case vc_string:
625 *var = rdata_var_new(vc_string);
626 string_v = rdata_string_new();
627
628 (*var)->u.string_v = string_v;
629 string_v->value = item->u.value->var->u.string_v->value;
630 break;
631 case vc_ref:
632 *var = rdata_var_new(vc_ref);
633 ref_v = rdata_ref_new();
634
635 (*var)->u.ref_v = ref_v;
636 ref_v->vref = item->u.value->var->u.ref_v->vref;
637 break;
638 default:
639 printf("Error: Unimplemented argument type.\n");
640 exit(1);
641
642 }
643}
644
645/** Construct a function AR. */
646void run_proc_ar_create(run_t *run, rdata_var_t *obj, stree_proc_t *proc,
647 run_proc_ar_t **rproc_ar)
648{
649 run_proc_ar_t *proc_ar;
650 run_block_ar_t *block_ar;
651
652 (void) run;
653
654 /* Create function activation record. */
655 proc_ar = run_proc_ar_new();
656 proc_ar->obj = obj;
657 proc_ar->proc = proc;
658 list_init(&proc_ar->block_ar);
659
660 proc_ar->retval = NULL;
661
662 /* Create special block activation record to hold function arguments. */
663 block_ar = run_block_ar_new();
664 intmap_init(&block_ar->vars);
665 list_append(&proc_ar->block_ar, block_ar);
666
667 *rproc_ar = proc_ar;
668}
669
670/** Fill arguments in a procedure AR.
671 *
672 * When invoking a procedure this is used to store the argument values
673 * in the activation record.
674 */
675void run_proc_ar_set_args(run_t *run, run_proc_ar_t *proc_ar, list_t *arg_vals)
676{
677 stree_fun_t *fun;
678 stree_prop_t *prop;
679 list_t *args;
680 stree_proc_arg_t *varg;
681 stree_symbol_t *outer_symbol;
682
683 run_block_ar_t *block_ar;
684 list_node_t *block_ar_n;
685 list_node_t *rarg_n, *parg_n;
686 list_node_t *cn;
687 rdata_item_t *rarg;
688 stree_proc_arg_t *parg;
689 rdata_var_t *var;
690 rdata_var_t *ref_var;
691 rdata_ref_t *ref;
692 rdata_array_t *array;
693 int n_vargs, idx;
694
695 (void) run;
696
697 /* AR should have been created with run_proc_ar_create(). */
698 assert(proc_ar->proc != NULL);
699 outer_symbol = proc_ar->proc->outer_symbol;
700
701 /*
702 * The procedure being activated should belong to a member function or
703 * property getter/setter.
704 */
705 switch (outer_symbol->sc) {
706 case sc_fun:
707 fun = symbol_to_fun(outer_symbol);
708 args = &fun->args;
709 varg = fun->varg;
710 break;
711 case sc_prop:
712 prop = symbol_to_prop(outer_symbol);
713 args = &prop->args;
714 varg = prop->varg;
715 break;
716 default:
717 assert(b_false);
718 }
719
720 /* Fetch first block activation record. */
721 block_ar_n = list_first(&proc_ar->block_ar);
722 assert(block_ar_n != NULL);
723 block_ar = list_node_data(block_ar_n, run_block_ar_t *);
724
725 /* Declare local variables to hold argument values. */
726 rarg_n = list_first(arg_vals);
727 parg_n = list_first(args);
728
729 while (parg_n != NULL) {
730 if (rarg_n == NULL) {
731 printf("Error: Too few arguments to '");
732 symbol_print_fqn(outer_symbol);
733 printf("'.\n");
734 exit(1);
735 }
736
737 rarg = list_node_data(rarg_n, rdata_item_t *);
738 parg = list_node_data(parg_n, stree_proc_arg_t *);
739
740 assert(rarg->ic == ic_value);
741
742 /* Construct a variable from the argument value. */
743 run_value_item_to_var(rarg, &var);
744
745 /* Declare variable using name of formal argument. */
746 intmap_set(&block_ar->vars, parg->name->sid, var);
747
748 rarg_n = list_next(arg_vals, rarg_n);
749 parg_n = list_next(args, parg_n);
750 }
751
752 if (varg != NULL) {
753 /* Function is variadic. Count number of variadic arguments. */
754 cn = rarg_n;
755 n_vargs = 0;
756 while (cn != NULL) {
757 n_vargs += 1;
758 cn = list_next(arg_vals, cn);
759 }
760
761 /* Prepare array to store variadic arguments. */
762 array = rdata_array_new(1);
763 array->extent[0] = n_vargs;
764 rdata_array_alloc_element(array);
765
766 /* Read variadic arguments. */
767
768 idx = 0;
769 while (rarg_n != NULL) {
770 rarg = list_node_data(rarg_n, rdata_item_t *);
771 assert(rarg->ic == ic_value);
772
773 rdata_var_write(array->element[idx], rarg->u.value);
774
775 rarg_n = list_next(arg_vals, rarg_n);
776 idx += 1;
777 }
778
779 var = rdata_var_new(vc_array);
780 var->u.array_v = array;
781
782 /* Create reference to the new array. */
783 ref_var = rdata_var_new(vc_ref);
784 ref = rdata_ref_new();
785 ref_var->u.ref_v = ref;
786 ref->vref = var;
787
788 /* Declare variable using name of formal argument. */
789 intmap_set(&block_ar->vars, varg->name->sid,
790 ref_var);
791 }
792
793 /* Check for excess real parameters. */
794 if (rarg_n != NULL) {
795 printf("Error: Too many arguments to '");
796 symbol_print_fqn(outer_symbol);
797 printf("'.\n");
798 exit(1);
799 }
800}
801
802/** Fill setter argument in a procedure AR.
803 *
804 * When invoking a setter this is used to store its argument value in its
805 * procedure activation record.
806 */
807void run_proc_ar_set_setter_arg(run_t *run, run_proc_ar_t *proc_ar,
808 rdata_item_t *arg_val)
809{
810 stree_prop_t *prop;
811 run_block_ar_t *block_ar;
812 list_node_t *block_ar_n;
813 rdata_var_t *var;
814
815 (void) run;
816
817 /* AR should have been created with run_proc_ar_create(). */
818 assert(proc_ar->proc != NULL);
819
820 /* The procedure being activated should belong to a property setter. */
821 prop = symbol_to_prop(proc_ar->proc->outer_symbol);
822 assert(prop != NULL);
823 assert(proc_ar->proc == prop->setter);
824
825 /* Fetch first block activation record. */
826 block_ar_n = list_first(&proc_ar->block_ar);
827 assert(block_ar_n != NULL);
828 block_ar = list_node_data(block_ar_n, run_block_ar_t *);
829
830 assert(arg_val->ic == ic_value);
831
832 /* Construct a variable from the argument value. */
833 run_value_item_to_var(arg_val, &var);
834
835 /* Declare variable using name of formal argument. */
836 intmap_set(&block_ar->vars, prop->setter_arg->name->sid, var);
837}
838
839/** Print function activation backtrace. */
840void run_print_fun_bt(run_t *run)
841{
842 list_node_t *node;
843 run_proc_ar_t *proc_ar;
844
845 printf("Backtrace:\n");
846 node = list_last(&run->thread_ar->proc_ar);
847 while (node != NULL) {
848 printf(" * ");
849 proc_ar = list_node_data(node, run_proc_ar_t *);
850 symbol_print_fqn(proc_ar->proc->outer_symbol);
851 printf("\n");
852
853 node = list_prev(&run->thread_ar->proc_ar, node);
854 }
855}
856
857/** Convert item to value item.
858 *
859 * If @a item is a value, we just return a copy. If @a item is an address,
860 * we read from the address.
861 */
862void run_cvt_value_item(run_t *run, rdata_item_t *item, rdata_item_t **ritem)
863{
864 rdata_value_t *value;
865
866 /*
867 * This can happen when trying to use output of a function which
868 * does not return a value.
869 */
870 if (item == NULL) {
871 printf("Error: Sub-expression has no value.\n");
872 exit(1);
873 }
874
875 /* Address item. Perform read operation. */
876 if (item->ic == ic_address) {
877 run_address_read(run, item->u.address, ritem);
878 return;
879 }
880
881 /* It already is a value, we can share the @c var. */
882 value = rdata_value_new();
883 value->var = item->u.value->var;
884 *ritem = rdata_item_new(ic_value);
885 (*ritem)->u.value = value;
886}
887
888/** Get item var-class.
889 *
890 * Get var-class of @a item, regardless whether it is a value or address.
891 * (I.e. the var class of the value or variable at the given address).
892 */
893var_class_t run_item_get_vc(run_t *run, rdata_item_t *item)
894{
895 var_class_t vc;
896 rdata_var_t *tpos;
897
898 (void) run;
899
900 switch (item->ic) {
901 case ic_value:
902 vc = item->u.value->var->vc;
903 break;
904 case ic_address:
905 switch (item->u.address->ac) {
906 case ac_var:
907 vc = item->u.address->u.var_a->vref->vc;
908 break;
909 case ac_prop:
910 /* Prefetch the value of the property. */
911 tpos = run_aprop_get_tpos(run, item->u.address);
912 vc = tpos->vc;
913 break;
914 default:
915 assert(b_false);
916 }
917 break;
918 default:
919 assert(b_false);
920 }
921
922 return vc;
923}
924
925/** Get pointer to current var node in temporary copy in property address.
926 *
927 * A property address refers to a specific @c var node in a property.
928 * This function will fetch a copy of the property value (by running
929 * its getter) if there is not a temporary copy in the address yet.
930 * It returns a pointer to the relevant @c var node in the temporary
931 * copy.
932 *
933 * @param run Runner object.
934 * @param addr Address of class @c ac_prop.
935 * @param Pointer to var node.
936 */
937static rdata_var_t *run_aprop_get_tpos(run_t *run, rdata_address_t *addr)
938{
939 rdata_item_t *ritem;
940
941 assert(addr->ac == ac_prop);
942
943 if (addr->u.prop_a->tvalue == NULL) {
944 /* Fetch value of the property. */
945 run_address_read(run, addr, &ritem);
946 assert(ritem->ic == ic_value);
947 addr->u.prop_a->tvalue = ritem->u.value;
948 addr->u.prop_a->tpos = addr->u.prop_a->tvalue->var;
949 }
950
951 return addr->u.prop_a->tpos;
952}
953
954/** Read data from an address.
955 *
956 * Return value stored in a variable at the specified address.
957 */
958void run_address_read(run_t *run, rdata_address_t *address,
959 rdata_item_t **ritem)
960{
961 (void) run;
962
963 switch (address->ac) {
964 case ac_var:
965 rdata_var_read(address->u.var_a->vref, ritem);
966 break;
967 case ac_prop:
968 run_aprop_read(run, address->u.prop_a, ritem);
969 break;
970 }
971
972 assert((*ritem)->ic == ic_value);
973}
974
975/** Write data to an address.
976 *
977 * Store @a value to the variable at @a address.
978 */
979void run_address_write(run_t *run, rdata_address_t *address,
980 rdata_value_t *value)
981{
982 (void) run;
983
984 switch (address->ac) {
985 case ac_var:
986 rdata_var_write(address->u.var_a->vref, value);
987 break;
988 case ac_prop:
989 run_aprop_write(run, address->u.prop_a, value);
990 break;
991 }
992}
993
994static void run_aprop_read(run_t *run, rdata_addr_prop_t *addr_prop,
995 rdata_item_t **ritem)
996{
997 rdata_deleg_t *deleg;
998 rdata_var_t *obj;
999 stree_symbol_t *prop_sym;
1000 stree_prop_t *prop;
1001
1002 run_proc_ar_t *proc_ar;
1003
1004 rdata_var_t *cvar;
1005
1006#ifdef DEBUG_RUN_TRACE
1007 printf("Read from property.\n");
1008#endif
1009 /*
1010 * If @c tvalue is present, we need to use the relevant part from that
1011 * instead of re-reading the whole thing.
1012 */
1013 if (addr_prop->tvalue != NULL) {
1014 /* Copy the value */
1015 rdata_var_copy(addr_prop->tpos, &cvar);
1016 *ritem = rdata_item_new(ic_value);
1017 (*ritem)->u.value = rdata_value_new();
1018 (*ritem)->u.value->var = cvar;
1019 return;
1020 }
1021
1022 if (addr_prop->apc == apc_named)
1023 deleg = addr_prop->u.named->prop_d;
1024 else
1025 deleg = addr_prop->u.indexed->object_d;
1026
1027 obj = deleg->obj;
1028 prop_sym = deleg->sym;
1029 prop = symbol_to_prop(prop_sym);
1030 assert(prop != NULL);
1031
1032 if (prop->getter == NULL) {
1033 printf("Error: Property is not readable.\n");
1034 exit(1);
1035 }
1036
1037 /* Create procedure activation record. */
1038 run_proc_ar_create(run, obj, prop->getter, &proc_ar);
1039
1040 /* Fill in arguments (indices). */
1041 if (addr_prop->apc == apc_indexed) {
1042 run_proc_ar_set_args(run, proc_ar,
1043 &addr_prop->u.indexed->args);
1044 }
1045
1046 /* Run getter. */
1047 run_proc(run, proc_ar, ritem);
1048
1049#ifdef DEBUG_RUN_TRACE
1050 printf("Getter returns ");
1051 rdata_item_print(*ritem);
1052 printf(".\n");
1053 printf("Done reading from property.\n");
1054#endif
1055}
1056
1057static void run_aprop_write(run_t *run, rdata_addr_prop_t *addr_prop,
1058 rdata_value_t *value)
1059{
1060 rdata_deleg_t *deleg;
1061 rdata_var_t *obj;
1062 stree_symbol_t *prop_sym;
1063 stree_prop_t *prop;
1064
1065 run_proc_ar_t *proc_ar;
1066 rdata_item_t *vitem;
1067 rdata_item_t *ritem;
1068
1069#ifdef DEBUG_RUN_TRACE
1070 printf("Write to property.\n");
1071#endif
1072 /* If @c tvalue is present, we need to modify it and write it back. */
1073 if (addr_prop->tvalue != NULL) {
1074 printf("Unimplemented: Read-modify-write property access.\n");
1075 exit(1);
1076 }
1077
1078 if (addr_prop->apc == apc_named)
1079 deleg = addr_prop->u.named->prop_d;
1080 else
1081 deleg = addr_prop->u.indexed->object_d;
1082
1083 obj = deleg->obj;
1084 prop_sym = deleg->sym;
1085 prop = symbol_to_prop(prop_sym);
1086 assert(prop != NULL);
1087
1088 if (prop->setter == NULL) {
1089 printf("Error: Property is not writable.\n");
1090 exit(1);
1091 }
1092
1093 vitem = rdata_item_new(ic_value);
1094 vitem->u.value = value;
1095
1096 /* Create procedure activation record. */
1097 run_proc_ar_create(run, obj, prop->setter, &proc_ar);
1098
1099 /* Fill in arguments (indices). */
1100 if (addr_prop->apc == apc_indexed) {
1101 run_proc_ar_set_args(run, proc_ar,
1102 &addr_prop->u.indexed->args);
1103 }
1104
1105 /* Fill in value argument for setter. */
1106 run_proc_ar_set_setter_arg(run, proc_ar, vitem);
1107
1108 /* Run setter. */
1109 run_proc(run, proc_ar, &ritem);
1110
1111 /* Setter should not return a value. */
1112 assert(ritem == NULL);
1113
1114#ifdef DEBUG_RUN_TRACE
1115 printf("Done writing to property.\n");
1116#endif
1117}
1118
1119/** Return reference to a variable.
1120 *
1121 * Constructs a reference (value item) pointing to @a var.
1122 */
1123void run_reference(run_t *run, rdata_var_t *var, rdata_item_t **res)
1124{
1125 rdata_ref_t *ref;
1126 rdata_var_t *ref_var;
1127 rdata_value_t *ref_value;
1128 rdata_item_t *ref_item;
1129
1130 (void) run;
1131
1132 /* Create reference to the variable. */
1133 ref = rdata_ref_new();
1134 ref_var = rdata_var_new(vc_ref);
1135 ref->vref = var;
1136 ref_var->u.ref_v = ref;
1137
1138 /* Construct value of the reference to return. */
1139 ref_item = rdata_item_new(ic_value);
1140 ref_value = rdata_value_new();
1141 ref_item->u.value = ref_value;
1142 ref_value->var = ref_var;
1143
1144 *res = ref_item;
1145}
1146
1147/** Return address of reference target.
1148 *
1149 * Takes a reference (address or value) and returns the address (item) of
1150 * the target of the reference.
1151 */
1152void run_dereference(run_t *run, rdata_item_t *ref, rdata_item_t **ritem)
1153{
1154 rdata_item_t *ref_val;
1155 rdata_item_t *item;
1156 rdata_address_t *address;
1157 rdata_addr_var_t *addr_var;
1158
1159#ifdef DEBUG_RUN_TRACE
1160 printf("run_dereference()\n");
1161#endif
1162 run_cvt_value_item(run, ref, &ref_val);
1163 assert(ref_val->u.value->var->vc == vc_ref);
1164
1165 item = rdata_item_new(ic_address);
1166 address = rdata_address_new(ac_var);
1167 addr_var = rdata_addr_var_new();
1168 item->u.address = address;
1169 address->u.var_a = addr_var;
1170 addr_var->vref = ref_val->u.value->var->u.ref_v->vref;
1171
1172 if (addr_var->vref == NULL) {
1173 printf("Error: Accessing null reference.\n");
1174 run_raise_error(run);
1175 *ritem = run_recovery_item(run);
1176 return;
1177 }
1178
1179#ifdef DEBUG_RUN_TRACE
1180 printf("vref set to %p\n", addr_var->vref);
1181#endif
1182 *ritem = item;
1183}
1184
1185run_thread_ar_t *run_thread_ar_new(void)
1186{
1187 run_thread_ar_t *thread_ar;
1188
1189 thread_ar = calloc(1, sizeof(run_thread_ar_t));
1190 if (thread_ar == NULL) {
1191 printf("Memory allocation failed.\n");
1192 exit(1);
1193 }
1194
1195 return thread_ar;
1196}
1197
1198run_proc_ar_t *run_proc_ar_new(void)
1199{
1200 run_proc_ar_t *proc_ar;
1201
1202 proc_ar = calloc(1, sizeof(run_proc_ar_t));
1203 if (proc_ar == NULL) {
1204 printf("Memory allocation failed.\n");
1205 exit(1);
1206 }
1207
1208 return proc_ar;
1209}
1210
1211run_block_ar_t *run_block_ar_new(void)
1212{
1213 run_block_ar_t *block_ar;
1214
1215 block_ar = calloc(1, sizeof(run_block_ar_t));
1216 if (block_ar == NULL) {
1217 printf("Memory allocation failed.\n");
1218 exit(1);
1219 }
1220
1221 return block_ar;
1222}
Note: See TracBrowser for help on using the repository browser.