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);
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]) * code->linenums.size();
192 size += sizeof(code->columnnums[0]) * code->columnnums.size();
194 size += sizeof(prog_header_t);
195 size += sizeof(prog_section_statement_t) * code->statements.size();
196 size += sizeof(prog_section_def_t) * code->defs.size();
197 size += sizeof(prog_section_field_t) * code->fields.size();
198 size += sizeof(prog_section_function_t) * code->functions.size();
199 size += sizeof(int32_t) * code->globals.size();
200 size += 1 * code->chars.size();
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 = code->statements.size();
213 code_header->defs.offset = code_header->statements.offset + (sizeof(prog_section_statement_t) * code->statements.size());
214 code_header->defs.length = code->defs.size();
215 code_header->fields.offset = code_header->defs.offset + (sizeof(prog_section_def_t) * code->defs.size());
216 code_header->fields.length = code->fields.size();
217 code_header->functions.offset = code_header->fields.offset + (sizeof(prog_section_field_t) * code->fields.size());
218 code_header->functions.length = code->functions.size();
219 code_header->globals.offset = code_header->functions.offset + (sizeof(prog_section_function_t) * code->functions.size());
220 code_header->globals.length = code->globals.size();
221 code_header->strings.offset = code_header->globals.offset + (sizeof(int32_t) * code->globals.size());
222 code_header->strings.length = code->chars.size();
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 code->chars.push_back('\0'); /* > */
235 code->chars.push_back('\0'); /* = */
236 code->chars.push_back('\0'); /* P */
239 /* ensure all data is in LE format */
240 util_swap_header(*code_header);
241 util_swap_statements(code->statements);
242 util_swap_defs_fields(code->defs);
243 util_swap_defs_fields(code->fields);
244 util_swap_functions(code->functions);
245 util_swap_globals(code->globals);
247 if (!OPTS_OPTION_BOOL(OPTION_QUIET)) {
249 con_out("writing '%s' and '%s'...\n", filename, lnofile);
251 con_out("writing '%s'\n", filename);
254 if (!OPTS_OPTION_BOOL(OPTION_QUIET) &&
255 !OPTS_OPTION_BOOL(OPTION_PP_ONLY))
258 con_out("\nOptimizations:\n");
259 for (i = 0; i < COUNT_OPTIMIZATIONS; ++i) {
260 if (opts_optimizationcount[i]) {
261 util_optimizationtostr(opts_opt_list[i].name, buffer, sizeof(buffer));
265 (unsigned int)opts_optimizationcount[i]
272 static void code_stats(const char *filename, const char *lnofile, code_t *code, prog_header_t *code_header) {
273 if (OPTS_OPTION_BOOL(OPTION_QUIET) ||
274 OPTS_OPTION_BOOL(OPTION_PP_ONLY))
277 con_out("\nFile statistics:\n");
279 con_out(" name: %s\n", filename);
280 con_out(" size: %u (bytes)\n", code_size_binary(code, code_header));
281 con_out(" crc: 0x%04X\n", code->crc);
285 con_out(" name: %s\n", lnofile);
286 con_out(" size: %u (bytes)\n", code_size_debug(code, code_header));
292 bool code_write(code_t *code, const char *filename, const char *lnofile) {
293 prog_header_t code_header;
296 code_create_header(code, &code_header, filename, lnofile);
299 uint32_t version = 1;
301 fp = fopen(lnofile, "wb");
305 util_endianswap(&version, 1, sizeof(version));
306 util_endianswap(&code->linenums[0], code->linenums.size(), sizeof(code->linenums[0]));
307 util_endianswap(&code->columnnums[0], code->columnnums.size(), sizeof(code->columnnums[0]));
309 if (fwrite("LNOF", 4, 1, fp) != 1 ||
310 fwrite(&version, sizeof(version), 1, fp) != 1 ||
311 fwrite(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 ||
312 fwrite(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 ||
313 fwrite(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 ||
314 fwrite(&code_header.statements.length, sizeof(code_header.statements.length), 1, fp) != 1 ||
315 fwrite(&code->linenums[0], sizeof(code->linenums[0]), code->linenums.size(), fp) != code->linenums.size() ||
316 fwrite(&code->columnnums[0], sizeof(code->columnnums[0]), code->columnnums.size(), fp) != code->columnnums.size())
318 con_err("failed to write lno file\n");
325 fp = fopen(filename, "wb");
329 if (1 != fwrite(&code_header, sizeof(prog_header_t) , 1 , fp) ||
330 code->statements.size() != fwrite(&code->statements[0], sizeof(prog_section_statement_t), code->statements.size(), fp) ||
331 code->defs.size() != fwrite(&code->defs[0], sizeof(prog_section_def_t) , code->defs.size() , fp) ||
332 code->fields.size() != fwrite(&code->fields[0], sizeof(prog_section_field_t) , code->fields.size() , fp) ||
333 code->functions.size() != fwrite(&code->functions[0], sizeof(prog_section_function_t) , code->functions.size() , fp) ||
334 code->globals.size() != fwrite(&code->globals[0], sizeof(int32_t) , code->globals.size() , fp) ||
335 code->chars.size() != fwrite(&code->chars[0], 1 , code->chars.size() , fp))
342 code_stats(filename, lnofile, code, &code_header);
346 void code_cleanup(code_t *code) {
347 util_htdel(code->string_cache);