5 * We could use the old method of casting to uintptr_t then to void*
6 * or qcint_t; however, it's incredibly unsafe for two reasons.
7 * 1) The compilers aliasing optimization can legally make it unstable
8 * (it's undefined behaviour).
10 * 2) The cast itself depends on fresh storage (newly allocated in which
11 * ever function is using the cast macros), the contents of which are
12 * transferred in a way that the obligation to release storage is not
20 /* Some sanity macros */
21 #define CODE_HASH_ENTER(ENTRY) ((ENTRY).enter)
22 #define CODE_HASH_LEAVE(ENTRY) ((ENTRY).leave)
24 void code_push_statement(code_t *code, prog_section_statement_t *stmt_in, lex_ctx_t ctx)
26 prog_section_statement_t stmt = *stmt_in;
28 if (OPTS_FLAG(TYPELESS_STORES)) {
29 switch (stmt.opcode) {
34 stmt.opcode = INSTR_LOAD_F;
40 stmt.opcode = INSTR_STORE_F;
43 case INSTR_STOREP_ENT:
44 case INSTR_STOREP_FLD:
45 case INSTR_STOREP_FNC:
46 stmt.opcode = INSTR_STOREP_F;
52 if (OPTS_FLAG(SORT_OPERANDS)) {
55 switch (stmt.opcode) {
72 if (stmt.o1.u1 < stmt.o2.u1) {
73 uint16_t a = stmt.o2.u1;
74 stmt.o1.u1 = stmt.o2.u1;
79 case INSTR_MUL_VF: pair = INSTR_MUL_FV; goto case_pair_gen;
80 case INSTR_MUL_FV: pair = INSTR_MUL_VF; goto case_pair_gen;
81 case INSTR_LT: pair = INSTR_GT; goto case_pair_gen;
82 case INSTR_GT: pair = INSTR_LT; goto case_pair_gen;
83 case INSTR_LE: pair = INSTR_GT; goto case_pair_gen;
84 case INSTR_GE: pair = INSTR_LE;
87 if (stmt.o1.u1 < stmt.o2.u1) {
88 uint16_t x = stmt.o1.u1;
89 stmt.o1.u1 = stmt.o2.u1;
97 vec_push(code->statements, stmt);
98 vec_push(code->linenums, (int)ctx.line);
99 vec_push(code->columnnums, (int)ctx.column);
102 void code_pop_statement(code_t *code)
104 vec_pop(code->statements);
105 vec_pop(code->linenums);
106 vec_pop(code->columnnums);
109 code_t *code_init() {
110 static lex_ctx_t empty_ctx = {0, 0, 0};
111 static prog_section_function_t empty_function = {0,0,0,0,0,0,0,{0,0,0,0,0,0,0,0}};
112 static prog_section_statement_t empty_statement = {0,{0},{0},{0}};
113 static prog_section_def_t empty_def = {0, 0, 0};
115 code_t *code = (code_t*)mem_a(sizeof(code_t));
118 memset(code, 0, sizeof(code_t));
120 code->string_cache = util_htnew(OPTS_OPTIMIZATION(OPTIM_OVERLAP_STRINGS) ? 0x100 : 1024);
123 * The way progs.dat is suppose to work is odd, there needs to be
124 * some null (empty) statements, functions, and 28 globals
127 vec_push(code->globals, 0);
129 vec_push(code->chars, '\0');
130 vec_push(code->functions, empty_function);
132 code_push_statement(code, &empty_statement, empty_ctx);
134 vec_push(code->defs, empty_def);
135 vec_push(code->fields, empty_def);
140 void *code_util_str_htgeth(hash_table_t *ht, const char *key, size_t bin);
142 uint32_t code_genstring(code_t *code, const char *str) {
144 code_hash_entry_t existing;
150 if (!code->string_cached_empty) {
151 code->string_cached_empty = vec_size(code->chars);
152 vec_push(code->chars, 0);
154 return code->string_cached_empty;
157 if (OPTS_OPTIMIZATION(OPTIM_OVERLAP_STRINGS)) {
158 hash = ((unsigned char*)str)[strlen(str)-1];
159 CODE_HASH_ENTER(existing) = code_util_str_htgeth(code->string_cache, str, hash);
161 hash = util_hthash(code->string_cache, str);
162 CODE_HASH_ENTER(existing) = util_htgeth(code->string_cache, str, hash);
165 if (CODE_HASH_ENTER(existing))
166 return CODE_HASH_LEAVE(existing);
168 CODE_HASH_LEAVE(existing) = vec_size(code->chars);
169 vec_append(code->chars, strlen(str)+1, str);
171 util_htseth(code->string_cache, str, hash, CODE_HASH_ENTER(existing));
172 return CODE_HASH_LEAVE(existing);
175 qcint_t code_alloc_field (code_t *code, size_t qcsize)
177 qcint_t pos = (qcint_t)code->entfields;
178 code->entfields += qcsize;
182 static size_t code_size_generic(code_t *code, prog_header_t *code_header, bool lno) {
185 size += 4; /* LNOF */
186 size += sizeof(uint32_t); /* version */
187 size += sizeof(code_header->defs.length);
188 size += sizeof(code_header->globals.length);
189 size += sizeof(code_header->fields.length);
190 size += sizeof(code_header->statements.length);
191 size += sizeof(code->linenums[0]) * vec_size(code->linenums);
192 size += sizeof(code->columnnums[0]) * vec_size(code->columnnums);
194 size += sizeof(prog_header_t);
195 size += sizeof(prog_section_statement_t) * vec_size(code->statements);
196 size += sizeof(prog_section_def_t) * vec_size(code->defs);
197 size += sizeof(prog_section_field_t) * vec_size(code->fields);
198 size += sizeof(prog_section_function_t) * vec_size(code->functions);
199 size += sizeof(int32_t) * vec_size(code->globals);
200 size += 1 * vec_size(code->chars);
205 #define code_size_binary(C, H) code_size_generic((C), (H), false)
206 #define code_size_debug(C, H) code_size_generic((C), (H), true)
208 static void code_create_header(code_t *code, prog_header_t *code_header, const char *filename, const char *lnofile) {
211 code_header->statements.offset = sizeof(prog_header_t);
212 code_header->statements.length = vec_size(code->statements);
213 code_header->defs.offset = code_header->statements.offset + (sizeof(prog_section_statement_t) * vec_size(code->statements));
214 code_header->defs.length = vec_size(code->defs);
215 code_header->fields.offset = code_header->defs.offset + (sizeof(prog_section_def_t) * vec_size(code->defs));
216 code_header->fields.length = vec_size(code->fields);
217 code_header->functions.offset = code_header->fields.offset + (sizeof(prog_section_field_t) * vec_size(code->fields));
218 code_header->functions.length = vec_size(code->functions);
219 code_header->globals.offset = code_header->functions.offset + (sizeof(prog_section_function_t) * vec_size(code->functions));
220 code_header->globals.length = vec_size(code->globals);
221 code_header->strings.offset = code_header->globals.offset + (sizeof(int32_t) * vec_size(code->globals));
222 code_header->strings.length = vec_size(code->chars);
223 code_header->version = 6;
224 code_header->skip = 0;
226 if (OPTS_OPTION_BOOL(OPTION_FORCECRC))
227 code_header->crc16 = OPTS_OPTION_U16(OPTION_FORCED_CRC);
229 code_header->crc16 = code->crc;
230 code_header->entfield = code->entfields;
232 if (OPTS_FLAG(DARKPLACES_STRING_TABLE_BUG)) {
234 vec_push(code->chars, '\0'); /* > */
235 vec_push(code->chars, '\0'); /* = */
236 vec_push(code->chars, '\0'); /* P */
239 /* ensure all data is in LE format */
240 util_swap_header(code_header);
243 * These are not part of the header but we ensure LE format here to save on duplicated
247 util_swap_statements (code->statements);
248 util_swap_defs_fields(code->defs);
249 util_swap_defs_fields(code->fields);
250 util_swap_functions (code->functions);
251 util_swap_globals (code->globals);
253 if (!OPTS_OPTION_BOOL(OPTION_QUIET)) {
255 con_out("writing '%s' and '%s'...\n", filename, lnofile);
257 con_out("writing '%s'\n", filename);
260 if (!OPTS_OPTION_BOOL(OPTION_QUIET) &&
261 !OPTS_OPTION_BOOL(OPTION_PP_ONLY))
264 con_out("\nOptimizations:\n");
265 for (i = 0; i < COUNT_OPTIMIZATIONS; ++i) {
266 if (opts_optimizationcount[i]) {
267 util_optimizationtostr(opts_opt_list[i].name, buffer, sizeof(buffer));
271 (unsigned int)opts_optimizationcount[i]
278 static void code_stats(const char *filename, const char *lnofile, code_t *code, prog_header_t *code_header) {
279 if (OPTS_OPTION_BOOL(OPTION_QUIET) ||
280 OPTS_OPTION_BOOL(OPTION_PP_ONLY))
283 con_out("\nFile statistics:\n");
285 con_out(" name: %s\n", filename);
286 con_out(" size: %u (bytes)\n", code_size_binary(code, code_header));
287 con_out(" crc: 0x%04X\n", code->crc);
291 con_out(" name: %s\n", lnofile);
292 con_out(" size: %u (bytes)\n", code_size_debug(code, code_header));
298 bool code_write(code_t *code, const char *filename, const char *lnofile) {
299 prog_header_t code_header;
302 code_create_header(code, &code_header, filename, lnofile);
305 uint32_t version = 1;
307 fp = fopen(lnofile, "wb");
311 util_endianswap(&version, 1, sizeof(version));
312 util_endianswap(code->linenums, vec_size(code->linenums), sizeof(code->linenums[0]));
313 util_endianswap(code->columnnums, vec_size(code->columnnums), sizeof(code->columnnums[0]));
315 if (fwrite("LNOF", 4, 1, fp) != 1 ||
316 fwrite(&version, sizeof(version), 1, fp) != 1 ||
317 fwrite(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 ||
318 fwrite(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 ||
319 fwrite(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 ||
320 fwrite(&code_header.statements.length, sizeof(code_header.statements.length), 1, fp) != 1 ||
321 fwrite(code->linenums, sizeof(code->linenums[0]), vec_size(code->linenums), fp) != vec_size(code->linenums) ||
322 fwrite(code->columnnums, sizeof(code->columnnums[0]), vec_size(code->columnnums), fp) != vec_size(code->columnnums))
324 con_err("failed to write lno file\n");
331 fp = fopen(filename, "wb");
335 if (1 != fwrite(&code_header, sizeof(prog_header_t) , 1 , fp) ||
336 vec_size(code->statements) != fwrite(code->statements, sizeof(prog_section_statement_t), vec_size(code->statements), fp) ||
337 vec_size(code->defs) != fwrite(code->defs, sizeof(prog_section_def_t) , vec_size(code->defs) , fp) ||
338 vec_size(code->fields) != fwrite(code->fields, sizeof(prog_section_field_t) , vec_size(code->fields) , fp) ||
339 vec_size(code->functions) != fwrite(code->functions, sizeof(prog_section_function_t) , vec_size(code->functions) , fp) ||
340 vec_size(code->globals) != fwrite(code->globals, sizeof(int32_t) , vec_size(code->globals) , fp) ||
341 vec_size(code->chars) != fwrite(code->chars, 1 , vec_size(code->chars) , fp))
348 code_stats(filename, lnofile, code, &code_header);
352 void code_cleanup(code_t *code) {
353 vec_free(code->statements);
354 vec_free(code->linenums);
355 vec_free(code->columnnums);
356 vec_free(code->defs);
357 vec_free(code->fields);
358 vec_free(code->functions);
359 vec_free(code->globals);
360 vec_free(code->chars);
362 util_htdel(code->string_cache);