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