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 code->statements.push_back(stmt);
98 code->linenums.push_back(ctx.line);
99 code->columnnums.push_back(ctx.column);
102 void code_pop_statement(code_t *code)
104 code->statements.pop_back();
105 code->linenums.pop_back();
106 code->columnnums.pop_back();
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 code->globals.push_back(0);
129 code->chars.push_back('\0');
130 code->functions.push_back(empty_function);
132 code_push_statement(code, &empty_statement, empty_ctx);
134 code->defs.push_back(empty_def);
135 code->fields.push_back(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 = code->chars.size();
152 code->chars.push_back(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) = code->chars.size();
169 code->chars.insert(code->chars.end(), str, str + strlen(str) + 1);
170 //vec_append(code->chars, strlen(str)+1, str);
172 util_htseth(code->string_cache, str, hash, CODE_HASH_ENTER(existing));
173 return CODE_HASH_LEAVE(existing);
176 qcint_t code_alloc_field (code_t *code, size_t qcsize)
178 qcint_t pos = (qcint_t)code->entfields;
179 code->entfields += qcsize;
183 static size_t code_size_generic(code_t *code, prog_header_t *code_header, bool lno) {
186 size += 4; /* LNOF */
187 size += sizeof(uint32_t); /* version */
188 size += sizeof(code_header->defs.length);
189 size += sizeof(code_header->globals.length);
190 size += sizeof(code_header->fields.length);
191 size += sizeof(code_header->statements.length);
192 size += sizeof(code->linenums[0]) * code->linenums.size();
193 size += sizeof(code->columnnums[0]) * code->columnnums.size();
195 size += sizeof(prog_header_t);
196 size += sizeof(prog_section_statement_t) * code->statements.size();
197 size += sizeof(prog_section_def_t) * code->defs.size();
198 size += sizeof(prog_section_field_t) * code->fields.size();
199 size += sizeof(prog_section_function_t) * code->functions.size();
200 size += sizeof(int32_t) * code->globals.size();
201 size += 1 * code->chars.size();
206 #define code_size_binary(C, H) code_size_generic((C), (H), false)
207 #define code_size_debug(C, H) code_size_generic((C), (H), true)
209 static void code_create_header(code_t *code, prog_header_t *code_header, const char *filename, const char *lnofile) {
212 code_header->statements.offset = sizeof(prog_header_t);
213 code_header->statements.length = code->statements.size();
214 code_header->defs.offset = code_header->statements.offset + (sizeof(prog_section_statement_t) * code->statements.size());
215 code_header->defs.length = code->defs.size();
216 code_header->fields.offset = code_header->defs.offset + (sizeof(prog_section_def_t) * code->defs.size());
217 code_header->fields.length = code->fields.size();
218 code_header->functions.offset = code_header->fields.offset + (sizeof(prog_section_field_t) * code->fields.size());
219 code_header->functions.length = code->functions.size();
220 code_header->globals.offset = code_header->functions.offset + (sizeof(prog_section_function_t) * code->functions.size());
221 code_header->globals.length = code->globals.size();
222 code_header->strings.offset = code_header->globals.offset + (sizeof(int32_t) * code->globals.size());
223 code_header->strings.length = code->chars.size();
224 code_header->version = 6;
225 code_header->skip = 0;
227 if (OPTS_OPTION_BOOL(OPTION_FORCECRC))
228 code_header->crc16 = OPTS_OPTION_U16(OPTION_FORCED_CRC);
230 code_header->crc16 = code->crc;
231 code_header->entfield = code->entfields;
233 if (OPTS_FLAG(DARKPLACES_STRING_TABLE_BUG)) {
235 code->chars.push_back('\0'); /* > */
236 code->chars.push_back('\0'); /* = */
237 code->chars.push_back('\0'); /* P */
240 /* ensure all data is in LE format */
241 util_swap_header(*code_header);
242 util_swap_statements(code->statements);
243 util_swap_defs_fields(code->defs);
244 util_swap_defs_fields(code->fields);
245 util_swap_functions(code->functions);
246 util_swap_globals(code->globals);
248 if (!OPTS_OPTION_BOOL(OPTION_QUIET)) {
250 con_out("writing '%s' and '%s'...\n", filename, lnofile);
252 con_out("writing '%s'\n", filename);
255 if (!OPTS_OPTION_BOOL(OPTION_QUIET) &&
256 !OPTS_OPTION_BOOL(OPTION_PP_ONLY))
259 con_out("\nOptimizations:\n");
260 for (i = 0; i < COUNT_OPTIMIZATIONS; ++i) {
261 if (opts_optimizationcount[i]) {
262 util_optimizationtostr(opts_opt_list[i].name, buffer, sizeof(buffer));
266 (unsigned int)opts_optimizationcount[i]
273 static void code_stats(const char *filename, const char *lnofile, code_t *code, prog_header_t *code_header) {
274 if (OPTS_OPTION_BOOL(OPTION_QUIET) ||
275 OPTS_OPTION_BOOL(OPTION_PP_ONLY))
278 con_out("\nFile statistics:\n");
280 con_out(" name: %s\n", filename);
281 con_out(" size: %u (bytes)\n", code_size_binary(code, code_header));
282 con_out(" crc: 0x%04X\n", code->crc);
286 con_out(" name: %s\n", lnofile);
287 con_out(" size: %u (bytes)\n", code_size_debug(code, code_header));
293 bool code_write(code_t *code, const char *filename, const char *lnofile) {
294 prog_header_t code_header;
297 code_create_header(code, &code_header, filename, lnofile);
300 uint32_t version = 1;
302 fp = fopen(lnofile, "wb");
306 util_endianswap(&version, 1, sizeof(version));
307 util_endianswap(&code->linenums[0], code->linenums.size(), sizeof(code->linenums[0]));
308 util_endianswap(&code->columnnums[0], code->columnnums.size(), sizeof(code->columnnums[0]));
310 if (fwrite("LNOF", 4, 1, fp) != 1 ||
311 fwrite(&version, sizeof(version), 1, fp) != 1 ||
312 fwrite(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 ||
313 fwrite(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 ||
314 fwrite(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 ||
315 fwrite(&code_header.statements.length, sizeof(code_header.statements.length), 1, fp) != 1 ||
316 fwrite(&code->linenums[0], sizeof(code->linenums[0]), code->linenums.size(), fp) != code->linenums.size() ||
317 fwrite(&code->columnnums[0], sizeof(code->columnnums[0]), code->columnnums.size(), fp) != code->columnnums.size())
319 con_err("failed to write lno file\n");
326 fp = fopen(filename, "wb");
330 if (1 != fwrite(&code_header, sizeof(prog_header_t) , 1 , fp) ||
331 code->statements.size() != fwrite(&code->statements[0], sizeof(prog_section_statement_t), code->statements.size(), fp) ||
332 code->defs.size() != fwrite(&code->defs[0], sizeof(prog_section_def_t) , code->defs.size() , fp) ||
333 code->fields.size() != fwrite(&code->fields[0], sizeof(prog_section_field_t) , code->fields.size() , fp) ||
334 code->functions.size() != fwrite(&code->functions[0], sizeof(prog_section_function_t) , code->functions.size() , fp) ||
335 code->globals.size() != fwrite(&code->globals[0], sizeof(int32_t) , code->globals.size() , fp) ||
336 code->chars.size() != fwrite(&code->chars[0], 1 , code->chars.size() , fp))
343 code_stats(filename, lnofile, code, &code_header);
347 void code_cleanup(code_t *code) {
348 util_htdel(code->string_cache);