1 /****************************************************************************
2  * Copyright (C) 2008 by Matteo Franchin                                    *
3  *                                                                          *
4  * This file is part of Box.                                                *
5  *                                                                          *
6  *   Box is free software: you can redistribute it and/or modify it         *
7  *   under the terms of the GNU Lesser General Public License as published  *
8  *   by the Free Software Foundation, either version 3 of the License, or   *
9  *   (at your option) any later version.                                    *
10  *                                                                          *
11  *   Box is distributed in the hope that it will be useful,                 *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
14  *   GNU Lesser General Public License for more details.                    *
15  *                                                                          *
16  *   You should have received a copy of the GNU Lesser General Public       *
17  *   License along with Box.  If not, see <http://www.gnu.org/licenses/>.   *
18  ****************************************************************************/
19 
20 #include <assert.h>
21 
22 #include "types.h"
23 #include "mem.h"
24 #include "vm_priv.h"
25 #include "vmsym.h"
26 #include "vmsymstuff.h"
27 #include "container.h"
28 #include "callable.h"
29 
30 
31 /*** jumps ******************************************************************/
32 
33 typedef struct {
34   int conditional;
35   BoxInt sheet_id;
36   BoxInt position;
37 } VMSymLabelRef;
38 
Assemble_Jmp(BoxVM * vmp,BoxVMSymID sym_id,BoxUInt sym_type,int defined,void * def,size_t def_size,void * ref,size_t ref_size)39 static BoxTask Assemble_Jmp(BoxVM *vmp, BoxVMSymID sym_id, BoxUInt sym_type,
40                             int defined, void *def, size_t def_size,
41                             void *ref, size_t ref_size) {
42   BoxInt rel_position = 0;
43   BoxOpId asm_code = BOXOP_JC_I;
44   VMSymLabelRef *label_ref = ref;
45 
46   assert(sym_type == BOXVMSYMTYPE_COND_JMP);
47   assert(ref_size == sizeof(VMSymLabelRef));
48   assert(ref);
49 
50   if (defined && def != NULL) {
51     BoxInt def_position, ref_position;
52     assert(def_size == sizeof(VMSymLabel));
53     def_position = ((VMSymLabel *) def)->position;
54     ref_position = label_ref->position;
55     rel_position = def_position - ref_position;
56   }
57 
58   asm_code = (label_ref->conditional) ? BOXOP_JC_I : BOXOP_JMP_I;
59   BoxVM_Assemble_Long(vmp, asm_code, BOXCONTCATEG_IMM, rel_position);
60   return BOXTASK_OK;
61 }
62 
BoxVMSym_New_Label(BoxVM * vmp)63 BoxVMSymID BoxVMSym_New_Label(BoxVM *vmp) {
64   return BoxVMSym_New(vmp, BOXVMSYMTYPE_COND_JMP, sizeof(VMSymLabel));
65 }
66 
BoxVMSym_Def_Label(BoxVM * vmp,BoxVMSymID sym_id,BoxInt sheet_id,BoxInt position)67 BoxTask BoxVMSym_Def_Label(BoxVM *vmp, BoxVMSymID sym_id,
68                       BoxInt sheet_id, BoxInt position) {
69   VMSymLabel label;
70   label.sheet_id = sheet_id;
71   label.position = position;
72   return BoxVMSym_Define(vmp, sym_id, & label);
73 }
74 
75 /* Same as VM_Label_Define, but sheet_id is the current active sheet and
76  * position is the current position in that sheet.
77  */
BoxVMSym_Def_Label_Here(BoxVM * vmp,BoxVMSymID label_sym_id)78 BoxTask BoxVMSym_Def_Label_Here(BoxVM *vmp, BoxVMSymID label_sym_id) {
79   BoxInt sheet_id, position;
80   sheet_id = vmp->proc_table.target_proc_num;
81   position = BoxArr_Num_Items(& vmp->proc_table.target_proc->code);
82   return BoxVMSym_Def_Label(vmp, label_sym_id, sheet_id, position);
83 }
84 
85 /* Same as VM_Label_New, but sheet_id is the current active sheet and
86  * position is the current position in that sheet.
87  */
BoxVMSym_New_Label_Here(BoxVM * vmp,BoxVMSymID * label_sym_id)88 BoxTask BoxVMSym_New_Label_Here(BoxVM *vmp, BoxVMSymID *label_sym_id) {
89   *label_sym_id = BoxVMSym_New_Label(vmp);
90   return BoxVMSym_Def_Label_Here(vmp, *label_sym_id);
91 }
92 
VM_Sym_Jmp_Generic(BoxVM * vmp,BoxVMSymID sym_id,int conditional)93 BoxTask VM_Sym_Jmp_Generic(BoxVM *vmp, BoxVMSymID sym_id, int conditional) {
94   VMSymLabelRef label_ref;
95   label_ref.conditional = conditional;
96   label_ref.sheet_id = vmp->proc_table.target_proc_num;
97   label_ref.position = BoxArr_Num_Items(& vmp->proc_table.target_proc->code);
98   return BoxVMSym_Code_Ref(vmp, sym_id, Assemble_Jmp,
99                            & label_ref, sizeof(VMSymLabelRef));
100 }
101 
BoxVMSym_Jc(BoxVM * vmp,BoxVMSymID sym_id)102 BoxTask BoxVMSym_Jc(BoxVM *vmp, BoxVMSymID sym_id) {
103   return VM_Sym_Jmp_Generic(vmp, sym_id, 1);
104 }
105 
BoxVMSym_Jmp(BoxVM * vmp,BoxVMSymID sym_id)106 BoxTask BoxVMSym_Jmp(BoxVM *vmp, BoxVMSymID sym_id) {
107   return VM_Sym_Jmp_Generic(vmp, sym_id, 0);
108 }
109 
BoxVMSym_Release_Label(BoxVM * vmp,BoxVMSymID sym_id)110 BoxTask BoxVMSym_Release_Label(BoxVM *vmp, BoxVMSymID sym_id) {
111   return BOXTASK_OK;
112 }
113 
114 /*** procedure headers ******************************************************/
115 
116 typedef struct {
117   BoxInt num_var[NUM_TYPES];
118   BoxInt num_reg[NUM_TYPES];
119 } ProcHead;
120 
121 /* This is the function which assembles the first code in procedures
122  * (the one which allocates registers and variables).
123  * Since at the beginning of a procedure the number of allocated registers
124  * and variables is unknown, we use the symbol manager to adjust
125  * automatically the header of procedures when the data is known.
126  */
Assemble_Proc_Head(BoxVM * vmp,BoxVMSymID sym_id,BoxUInt sym_type,int defined,void * def,size_t def_size,void * ref,size_t ref_size)127 static BoxTask Assemble_Proc_Head(BoxVM *vmp, BoxVMSymID sym_id, BoxUInt sym_type,
128                                   int defined, void *def, size_t def_size,
129                                   void *ref, size_t ref_size) {
130   ProcHead *ph = (ProcHead *) def;
131   static BoxInt asm_code[NUM_TYPES] = {BOXOP_NEWC_II, BOXOP_NEWI_II,
132                                        BOXOP_NEWR_II, BOXOP_NEWP_II,
133                                        BOXOP_NEWO_II};
134   int i;
135 
136   assert(sym_type == BOXVMSYMTYPE_PROC_HEAD);
137   assert(def_size == sizeof(ProcHead));
138   assert(def != NULL);
139 
140   for(i = 0; i < NUM_TYPES; i++) {
141     BoxInt nv = ph->num_var[i], nr = ph->num_reg[i];
142     assert(nv >= 0 && nr >= 0);
143     BoxVM_Assemble_Long(vmp, asm_code[i],
144                         BOXCONTCATEG_IMM, nv, BOXCONTCATEG_IMM, nr);
145     /* ^^^ should use BoxVM_Assemble_Long for more than 127 regs/vars */
146   }
147   return BOXTASK_OK;
148 }
149 
BoxVMSym_Assemble_Proc_Head(BoxVM * vm,BoxVMSymID * sym_id)150 BoxTask BoxVMSym_Assemble_Proc_Head(BoxVM *vm, BoxVMSymID *sym_id) {
151   *sym_id = BoxVMSym_New(vm, BOXVMSYMTYPE_PROC_HEAD, sizeof(ProcHead));
152   return BoxVMSym_Code_Ref(vm, *sym_id, Assemble_Proc_Head, NULL, 0);
153 }
154 
BoxVMSym_Def_Proc_Head(BoxVM * vmp,BoxVMSymID sym_id,BoxInt * num_var,BoxInt * num_reg)155 BoxTask BoxVMSym_Def_Proc_Head(BoxVM *vmp, BoxVMSymID sym_id,
156                                BoxInt *num_var, BoxInt *num_reg) {
157   ProcHead ph;
158   int i;
159   for(i = 0; i < NUM_TYPES; i++) {
160     ph.num_var[i] = num_var[i];
161     ph.num_reg[i] = num_reg[i];
162   }
163   return BoxVMSym_Define(vmp, sym_id, & ph);
164 }
165 
166 /*** callables **************************************************************/
167 
168 /* Temporary, very ugly stuff... */
169 
170 /**
171  * @brief Data necessary to define a procedure.
172  */
173 typedef struct {
174   BoxCallable *callable;
175   BoxCCallOld fn_ptr;
176 } MyProcDef;
177 
178 BoxBool
BoxVMSym_Proc_Is_Implemented(BoxVM * vm,BoxVMSymID sym_id,const char ** c_name)179 BoxVMSym_Proc_Is_Implemented(BoxVM *vm, BoxVMSymID sym_id,
180                              const char **c_name) {
181   MyProcDef *proc_def = BoxVMSym_Get_Definition(vm, sym_id);
182   assert(proc_def);
183   *c_name = BoxCallable_Get_Uid(proc_def->callable);
184   return BoxCallable_Is_Implemented(proc_def->callable);
185 }
186 
187 BoxBool
BoxVMSym_Define_Proc(BoxVM * vm,BoxVMSymID sym_id,BoxCCallOld fn_ptr)188 BoxVMSym_Define_Proc(BoxVM *vm, BoxVMSymID sym_id, BoxCCallOld fn_ptr) {
189   MyProcDef *proc_def = BoxVMSym_Get_Definition(vm, sym_id);
190   assert(proc_def);
191 
192   if (fn_ptr)
193     proc_def->fn_ptr = fn_ptr;
194 
195   if (BoxVMSym_Define(vm, sym_id, NULL) != BOXTASK_OK)
196     return BOXBOOL_FALSE;
197   return BOXBOOL_TRUE;
198 }
199 
200 static BoxTask
My_Resolve_Proc_Ref(BoxVM * vm,BoxVMSymID sym_id,BoxUInt sym_type,int defined,void * def,size_t def_size,void * ref,size_t ref_size)201 My_Resolve_Proc_Ref(BoxVM *vm, BoxVMSymID sym_id, BoxUInt sym_type,
202                     int defined, void *def, size_t def_size,
203                     void *ref, size_t ref_size) {
204   MyProcDef *proc_def = def;
205   BoxCallable *cb;
206   BoxTask success;
207 
208   assert(sym_type == BOXVMSYMTYPE_PROC && proc_def && defined);
209 
210   if (BoxCallable_Is_Implemented(proc_def->callable))
211     return BOXTASK_OK;
212 
213   cb = BoxCallable_Link(proc_def->callable);
214   cb = BoxCallable_Define_From_CCallOld(cb, proc_def->fn_ptr);
215   success = (cb) ? BOXTASK_OK : BOXTASK_FAILURE;
216   (void) BoxCallable_Unlink(cb);
217   return success;
218 }
219 
220 /*
221  */
222 BoxBool
BoxVMSym_Reference_Proc(BoxVM * vm,BoxCallable * cb)223 BoxVMSym_Reference_Proc(BoxVM *vm, BoxCallable *cb) {
224   MyProcDef proc_def;
225   const char *name = BoxCallable_Get_Uid(cb);
226 
227   assert(vm);
228 
229   //if (BoxCallable_Is_Implemented(cb))
230   //  return BOXBOOL_TRUE;
231 
232   proc_def.callable = BoxCallable_Link(cb);
233 
234   /* Create a new PROC symbol. */
235   BoxVMSymID sym_id = BoxVMSym_Create(vm, BOXVMSYMTYPE_PROC,
236                                       & proc_def, sizeof(MyProcDef));
237   assert(sym_id != BOXVMSYMID_NONE);
238 
239   if (name)
240     BoxVMSym_Set_Name(vm, sym_id, name);
241 
242   /* Create a new reference to the symbol. */
243   BoxVMSym_Ref(vm, sym_id, My_Resolve_Proc_Ref, NULL, 0, BOXVMSYM_AUTO);
244   return BOXBOOL_TRUE;
245 }
246 
247