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 void *code_t::operator new(std::size_t bytes) {
113 void code_t::operator delete(void *ptr) {
119 static lex_ctx_t empty_ctx = {0, 0, 0};
120 static prog_section_function_t empty_function = {0,0,0,0,0,0,0,{0,0,0,0,0,0,0,0}};
121 static prog_section_statement_t empty_statement = {0,{0},{0},{0}};
122 static prog_section_def_t empty_def = {0, 0, 0};
124 string_cache = util_htnew(OPTS_OPTIMIZATION(OPTIM_OVERLAP_STRINGS) ? 0x100 : 1024);
126 // The way progs.dat is suppose to work is odd, there needs to be
127 // some null (empty) statements, functions, and 28 globals
128 globals.insert(globals.begin(), 28, 0);
130 chars.push_back('\0');
131 functions.push_back(empty_function);
133 code_push_statement(this, &empty_statement, empty_ctx);
135 defs.push_back(empty_def);
136 fields.push_back(empty_def);
141 util_htdel(string_cache);
144 void *code_util_str_htgeth(hash_table_t *ht, const char *key, size_t bin);
146 uint32_t code_genstring(code_t *code, const char *str) {
148 code_hash_entry_t existing;
154 if (!code->string_cached_empty) {
155 code->string_cached_empty = code->chars.size();
156 code->chars.push_back(0);
158 return code->string_cached_empty;
161 if (OPTS_OPTIMIZATION(OPTIM_OVERLAP_STRINGS)) {
162 hash = ((unsigned char*)str)[strlen(str)-1];
163 CODE_HASH_ENTER(existing) = code_util_str_htgeth(code->string_cache, str, hash);
165 hash = util_hthash(code->string_cache, str);
166 CODE_HASH_ENTER(existing) = util_htgeth(code->string_cache, str, hash);
169 if (CODE_HASH_ENTER(existing))
170 return CODE_HASH_LEAVE(existing);
172 CODE_HASH_LEAVE(existing) = code->chars.size();
173 code->chars.insert(code->chars.end(), str, str + strlen(str) + 1);
175 util_htseth(code->string_cache, str, hash, CODE_HASH_ENTER(existing));
176 return CODE_HASH_LEAVE(existing);
179 qcint_t code_alloc_field (code_t *code, size_t qcsize)
181 qcint_t pos = (qcint_t)code->entfields;
182 code->entfields += qcsize;
186 static size_t code_size_generic(code_t *code, prog_header_t *code_header, bool lno) {
189 size += 4; /* LNOF */
190 size += sizeof(uint32_t); /* version */
191 size += sizeof(code_header->defs.length);
192 size += sizeof(code_header->globals.length);
193 size += sizeof(code_header->fields.length);
194 size += sizeof(code_header->statements.length);
195 size += sizeof(code->linenums[0]) * code->linenums.size();
196 size += sizeof(code->columnnums[0]) * code->columnnums.size();
198 size += sizeof(prog_header_t);
199 size += sizeof(prog_section_statement_t) * code->statements.size();
200 size += sizeof(prog_section_def_t) * code->defs.size();
201 size += sizeof(prog_section_field_t) * code->fields.size();
202 size += sizeof(prog_section_function_t) * code->functions.size();
203 size += sizeof(int32_t) * code->globals.size();
204 size += 1 * code->chars.size();
209 #define code_size_binary(C, H) code_size_generic((C), (H), false)
210 #define code_size_debug(C, H) code_size_generic((C), (H), true)
212 static void code_create_header(code_t *code, prog_header_t *code_header, const char *filename, const char *lnofile) {
215 code_header->statements.offset = sizeof(prog_header_t);
216 code_header->statements.length = code->statements.size();
217 code_header->defs.offset = code_header->statements.offset + (sizeof(prog_section_statement_t) * code->statements.size());
218 code_header->defs.length = code->defs.size();
219 code_header->fields.offset = code_header->defs.offset + (sizeof(prog_section_def_t) * code->defs.size());
220 code_header->fields.length = code->fields.size();
221 code_header->functions.offset = code_header->fields.offset + (sizeof(prog_section_field_t) * code->fields.size());
222 code_header->functions.length = code->functions.size();
223 code_header->globals.offset = code_header->functions.offset + (sizeof(prog_section_function_t) * code->functions.size());
224 code_header->globals.length = code->globals.size();
225 code_header->strings.offset = code_header->globals.offset + (sizeof(int32_t) * code->globals.size());
226 code_header->strings.length = code->chars.size();
227 code_header->version = 6;
228 code_header->skip = 0;
230 if (OPTS_OPTION_BOOL(OPTION_FORCECRC))
231 code_header->crc16 = OPTS_OPTION_U16(OPTION_FORCED_CRC);
233 code_header->crc16 = code->crc;
234 code_header->entfield = code->entfields;
236 if (OPTS_FLAG(DARKPLACES_STRING_TABLE_BUG)) {
238 code->chars.push_back('\0'); /* > */
239 code->chars.push_back('\0'); /* = */
240 code->chars.push_back('\0'); /* P */
243 /* ensure all data is in LE format */
244 util_swap_header(*code_header);
245 util_swap_statements(code->statements);
246 util_swap_defs_fields(code->defs);
247 util_swap_defs_fields(code->fields);
248 util_swap_functions(code->functions);
249 util_swap_globals(code->globals);
251 if (!OPTS_OPTION_BOOL(OPTION_QUIET)) {
253 con_out("writing '%s' and '%s'...\n", filename, lnofile);
255 con_out("writing '%s'\n", filename);
258 if (!OPTS_OPTION_BOOL(OPTION_QUIET) &&
259 !OPTS_OPTION_BOOL(OPTION_PP_ONLY))
262 con_out("\nOptimizations:\n");
263 for (i = 0; i < COUNT_OPTIMIZATIONS; ++i) {
264 if (opts_optimizationcount[i]) {
265 util_optimizationtostr(opts_opt_list[i].name, buffer, sizeof(buffer));
269 (unsigned int)opts_optimizationcount[i]
276 static void code_stats(const char *filename, const char *lnofile, code_t *code, prog_header_t *code_header) {
277 if (OPTS_OPTION_BOOL(OPTION_QUIET) ||
278 OPTS_OPTION_BOOL(OPTION_PP_ONLY))
281 con_out("\nFile statistics:\n");
283 con_out(" name: %s\n", filename);
284 con_out(" size: %u (bytes)\n", code_size_binary(code, code_header));
285 con_out(" crc: 0x%04X\n", code->crc);
289 con_out(" name: %s\n", lnofile);
290 con_out(" size: %u (bytes)\n", code_size_debug(code, code_header));
296 bool code_write(code_t *code, const char *filename, const char *lnofile) {
297 prog_header_t code_header;
300 code_create_header(code, &code_header, filename, lnofile);
303 uint32_t version = 1;
305 fp = fopen(lnofile, "wb");
309 util_endianswap(&version, 1, sizeof(version));
310 util_endianswap(&code->linenums[0], code->linenums.size(), sizeof(code->linenums[0]));
311 util_endianswap(&code->columnnums[0], code->columnnums.size(), sizeof(code->columnnums[0]));
313 if (fwrite("LNOF", 4, 1, fp) != 1 ||
314 fwrite(&version, sizeof(version), 1, fp) != 1 ||
315 fwrite(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 ||
316 fwrite(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 ||
317 fwrite(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 ||
318 fwrite(&code_header.statements.length, sizeof(code_header.statements.length), 1, fp) != 1 ||
319 fwrite(&code->linenums[0], sizeof(code->linenums[0]), code->linenums.size(), fp) != code->linenums.size() ||
320 fwrite(&code->columnnums[0], sizeof(code->columnnums[0]), code->columnnums.size(), fp) != code->columnnums.size())
322 con_err("failed to write lno file\n");
329 fp = fopen(filename, "wb");
333 if (1 != fwrite(&code_header, sizeof(prog_header_t) , 1 , fp) ||
334 code->statements.size() != fwrite(&code->statements[0], sizeof(prog_section_statement_t), code->statements.size(), fp) ||
335 code->defs.size() != fwrite(&code->defs[0], sizeof(prog_section_def_t) , code->defs.size() , fp) ||
336 code->fields.size() != fwrite(&code->fields[0], sizeof(prog_section_field_t) , code->fields.size() , fp) ||
337 code->functions.size() != fwrite(&code->functions[0], sizeof(prog_section_function_t) , code->functions.size() , fp) ||
338 code->globals.size() != fwrite(&code->globals[0], sizeof(int32_t) , code->globals.size() , fp) ||
339 code->chars.size() != fwrite(&code->chars[0], 1 , code->chars.size() , fp))
346 code_stats(filename, lnofile, code, &code_header);