js/src/jskwgen.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include <assert.h>
michael@0 8 #include <ctype.h>
michael@0 9 #include <stdarg.h>
michael@0 10 #include <stdio.h>
michael@0 11 #include <stdlib.h>
michael@0 12 #include <string.h>
michael@0 13
michael@0 14 #include "vm/Keywords.h"
michael@0 15
michael@0 16 static const char * const keyword_list[] = {
michael@0 17 #define KEYWORD_STRING(keyword, name, type, version) #keyword,
michael@0 18 FOR_EACH_JAVASCRIPT_KEYWORD(KEYWORD_STRING)
michael@0 19 #undef KEYWORD_STRING
michael@0 20 };
michael@0 21
michael@0 22 struct gen_opt {
michael@0 23 FILE *output; /* output file for generated source */
michael@0 24 unsigned use_if_threshold; /* max number of choices to generate
michael@0 25 "if" selector instead of "switch" */
michael@0 26 unsigned char_tail_test_threshold; /* max number of unprocessed columns
michael@0 27 to use inlined char compare
michael@0 28 for remaining chars and not generic
michael@0 29 string compare code */
michael@0 30 unsigned indent_level; /* current source identation level */
michael@0 31 };
michael@0 32
michael@0 33 static unsigned column_to_compare;
michael@0 34
michael@0 35 static int
michael@0 36 length_comparator(const void *a, const void *b)
michael@0 37 {
michael@0 38 const char *str1 = keyword_list[*(unsigned *)a];
michael@0 39 const char *str2 = keyword_list[*(unsigned *)b];
michael@0 40 return (int)strlen(str1) - (int)strlen(str2);
michael@0 41 }
michael@0 42
michael@0 43 static int
michael@0 44 column_comparator(const void *a, const void *b)
michael@0 45 {
michael@0 46 const char *str1 = keyword_list[*(unsigned *)a];
michael@0 47 const char *str2 = keyword_list[*(unsigned *)b];
michael@0 48 return (int)str1[column_to_compare] - (int)str2[column_to_compare];
michael@0 49 }
michael@0 50
michael@0 51 static unsigned
michael@0 52 count_different_lengths(unsigned indexes[], unsigned nelem)
michael@0 53 {
michael@0 54 unsigned nlength, current_length, i, l;
michael@0 55
michael@0 56 current_length = 0;
michael@0 57 nlength = 0;
michael@0 58 for (i = 0; i != nelem; ++i) {
michael@0 59 l = (unsigned)strlen(keyword_list[indexes[i]]);
michael@0 60 assert(l != 0);
michael@0 61 if (current_length != l) {
michael@0 62 ++nlength;
michael@0 63 current_length = l;
michael@0 64 }
michael@0 65 }
michael@0 66 return nlength;
michael@0 67 }
michael@0 68
michael@0 69 static void
michael@0 70 find_char_span_and_count(unsigned indexes[], unsigned nelem, unsigned column,
michael@0 71 unsigned *span_result, unsigned *count_result)
michael@0 72 {
michael@0 73 unsigned i, count;
michael@0 74 unsigned char c, prev, minc, maxc;
michael@0 75
michael@0 76 assert(nelem != 0);
michael@0 77 minc = maxc = prev = (unsigned char)keyword_list[indexes[0]][column];
michael@0 78 count = 1;
michael@0 79 for (i = 1; i != nelem; ++i) {
michael@0 80 c = (unsigned char)keyword_list[indexes[i]][column];
michael@0 81 if (prev != c) {
michael@0 82 prev = c;
michael@0 83 ++count;
michael@0 84 if (minc > c) {
michael@0 85 minc = c;
michael@0 86 } else if (maxc < c) {
michael@0 87 maxc = c;
michael@0 88 }
michael@0 89 }
michael@0 90 }
michael@0 91
michael@0 92 *span_result = maxc - minc + 1;
michael@0 93 *count_result = count;
michael@0 94 }
michael@0 95
michael@0 96 static unsigned
michael@0 97 find_optimal_switch_column(struct gen_opt *opt,
michael@0 98 unsigned indexes[], unsigned nelem,
michael@0 99 unsigned columns[], unsigned unprocessed_columns,
michael@0 100 int *use_if_result)
michael@0 101 {
michael@0 102 unsigned i;
michael@0 103 unsigned span, min_span, min_span_index;
michael@0 104 unsigned nchar, min_nchar, min_nchar_index;
michael@0 105
michael@0 106 assert(unprocessed_columns != 0);
michael@0 107 i = 0;
michael@0 108 min_nchar = min_span = (unsigned)-1;
michael@0 109 min_nchar_index = min_span_index = 0;
michael@0 110 do {
michael@0 111 column_to_compare = columns[i];
michael@0 112 qsort(indexes, nelem, sizeof(indexes[0]), column_comparator);
michael@0 113 find_char_span_and_count(indexes, nelem, column_to_compare,
michael@0 114 &span, &nchar);
michael@0 115 assert(span != 0);
michael@0 116 if (span == 1) {
michael@0 117 assert(nchar == 1);
michael@0 118 *use_if_result = 1;
michael@0 119 return 1;
michael@0 120 }
michael@0 121 assert(nchar != 1);
michael@0 122 if (min_span > span) {
michael@0 123 min_span = span;
michael@0 124 min_span_index = i;
michael@0 125 }
michael@0 126 if (min_nchar > nchar) {
michael@0 127 min_nchar = nchar;
michael@0 128 min_nchar_index = i;
michael@0 129 }
michael@0 130 } while (++i != unprocessed_columns);
michael@0 131
michael@0 132 if (min_nchar <= opt->use_if_threshold) {
michael@0 133 *use_if_result = 1;
michael@0 134 i = min_nchar_index;
michael@0 135 } else {
michael@0 136 *use_if_result = 0;
michael@0 137 i = min_span_index;
michael@0 138 }
michael@0 139
michael@0 140 /*
michael@0 141 * Restore order corresponding to i if it was destroyed by
michael@0 142 * subsequent sort.
michael@0 143 */
michael@0 144 if (i != unprocessed_columns - 1) {
michael@0 145 column_to_compare = columns[i];
michael@0 146 qsort(indexes, nelem, sizeof(indexes[0]), column_comparator);
michael@0 147 }
michael@0 148
michael@0 149 return i;
michael@0 150 }
michael@0 151
michael@0 152
michael@0 153 static void
michael@0 154 p(struct gen_opt *opt, const char *format, ...)
michael@0 155 {
michael@0 156 va_list ap;
michael@0 157
michael@0 158 va_start(ap, format);
michael@0 159 vfprintf(opt->output, format, ap);
michael@0 160 va_end(ap);
michael@0 161 }
michael@0 162
michael@0 163 /* Size for '\xxx' where xxx is octal escape */
michael@0 164 #define MIN_QUOTED_CHAR_BUFFER 7
michael@0 165
michael@0 166 static char *
michael@0 167 qchar(char c, char *quoted_buffer)
michael@0 168 {
michael@0 169 char *s;
michael@0 170
michael@0 171 s = quoted_buffer;
michael@0 172 *s++ = '\'';
michael@0 173 switch (c) {
michael@0 174 case '\n': c = 'n'; goto one_char_escape;
michael@0 175 case '\r': c = 'r'; goto one_char_escape;
michael@0 176 case '\t': c = 't'; goto one_char_escape;
michael@0 177 case '\f': c = 't'; goto one_char_escape;
michael@0 178 case '\0': c = '0'; goto one_char_escape;
michael@0 179 case '\'': goto one_char_escape;
michael@0 180 one_char_escape:
michael@0 181 *s++ = '\\';
michael@0 182 break;
michael@0 183 default:
michael@0 184 if (!isprint(c)) {
michael@0 185 *s++ = '\\';
michael@0 186 *s++ = (char)('0' + (0x3 & (((unsigned char)c) >> 6)));
michael@0 187 *s++ = (char)('0' + (0x7 & (((unsigned char)c) >> 3)));
michael@0 188 c = (char)('0' + (0x7 & ((unsigned char)c)));
michael@0 189 }
michael@0 190 }
michael@0 191 *s++ = c;
michael@0 192 *s++ = '\'';
michael@0 193 *s = '\0';
michael@0 194 assert(s + 1 <= quoted_buffer + MIN_QUOTED_CHAR_BUFFER);
michael@0 195 return quoted_buffer;
michael@0 196 }
michael@0 197
michael@0 198 static void
michael@0 199 nl(struct gen_opt *opt)
michael@0 200 {
michael@0 201 putc('\n', opt->output);
michael@0 202 }
michael@0 203
michael@0 204 static void
michael@0 205 indent(struct gen_opt *opt)
michael@0 206 {
michael@0 207 unsigned n = opt->indent_level;
michael@0 208 while (n != 0) {
michael@0 209 --n;
michael@0 210 fputs(" ", opt->output);
michael@0 211 }
michael@0 212 }
michael@0 213
michael@0 214 static void
michael@0 215 line(struct gen_opt *opt, const char *format, ...)
michael@0 216 {
michael@0 217 va_list ap;
michael@0 218
michael@0 219 indent(opt);
michael@0 220 va_start(ap, format);
michael@0 221 vfprintf(opt->output, format, ap);
michael@0 222 va_end(ap);
michael@0 223 nl(opt);
michael@0 224 }
michael@0 225
michael@0 226 static void
michael@0 227 generate_letter_switch_r(struct gen_opt *opt,
michael@0 228 unsigned indexes[], unsigned nelem,
michael@0 229 unsigned columns[], unsigned unprocessed_columns)
michael@0 230 {
michael@0 231 char qbuf[MIN_QUOTED_CHAR_BUFFER];
michael@0 232
michael@0 233 assert(nelem != 0);
michael@0 234 if (nelem == 1) {
michael@0 235 unsigned kw_index = indexes[0];
michael@0 236 const char *keyword = keyword_list[kw_index];
michael@0 237
michael@0 238 if (unprocessed_columns == 0) {
michael@0 239 line(opt, "JSKW_GOT_MATCH(%u) /* %s */", kw_index, keyword);
michael@0 240 } else if (unprocessed_columns > opt->char_tail_test_threshold) {
michael@0 241 line(opt, "JSKW_TEST_GUESS(%u) /* %s */", kw_index, keyword);
michael@0 242 } else {
michael@0 243 unsigned i, column;
michael@0 244
michael@0 245 indent(opt); p(opt, "if (");
michael@0 246 for (i = 0; i != unprocessed_columns; ++i) {
michael@0 247 column = columns[i];
michael@0 248 qchar(keyword[column], qbuf);
michael@0 249 p(opt, "%sJSKW_AT(%u)==%s", (i == 0) ? "" : " && ",
michael@0 250 column, qbuf);
michael@0 251 }
michael@0 252 p(opt, ") {"); nl(opt);
michael@0 253 ++opt->indent_level;
michael@0 254 line(opt, "JSKW_GOT_MATCH(%u) /* %s */", kw_index, keyword);
michael@0 255 --opt->indent_level;
michael@0 256 line(opt, "}");
michael@0 257 line(opt, "JSKW_NO_MATCH()");
michael@0 258 }
michael@0 259 } else {
michael@0 260 unsigned optimal_column_index, optimal_column;
michael@0 261 unsigned i;
michael@0 262 int use_if;
michael@0 263 char current;
michael@0 264
michael@0 265 assert(unprocessed_columns != 0);
michael@0 266 optimal_column_index = find_optimal_switch_column(opt, indexes, nelem,
michael@0 267 columns,
michael@0 268 unprocessed_columns,
michael@0 269 &use_if);
michael@0 270 optimal_column = columns[optimal_column_index];
michael@0 271 columns[optimal_column_index] = columns[unprocessed_columns - 1];
michael@0 272
michael@0 273 if (!use_if)
michael@0 274 line(opt, "switch (JSKW_AT(%u)) {", optimal_column);
michael@0 275
michael@0 276 current = keyword_list[indexes[0]][optimal_column];
michael@0 277 for (i = 0; i != nelem;) {
michael@0 278 unsigned same_char_begin = i;
michael@0 279 char next = current;
michael@0 280
michael@0 281 for (++i; i != nelem; ++i) {
michael@0 282 next = keyword_list[indexes[i]][optimal_column];
michael@0 283 if (next != current)
michael@0 284 break;
michael@0 285 }
michael@0 286 qchar(current, qbuf);
michael@0 287 if (use_if) {
michael@0 288 line(opt, "if (JSKW_AT(%u) == %s) {", optimal_column, qbuf);
michael@0 289 } else {
michael@0 290 line(opt, " case %s:", qbuf);
michael@0 291 }
michael@0 292 ++opt->indent_level;
michael@0 293 generate_letter_switch_r(opt, indexes + same_char_begin,
michael@0 294 i - same_char_begin,
michael@0 295 columns, unprocessed_columns - 1);
michael@0 296 --opt->indent_level;
michael@0 297 if (use_if) {
michael@0 298 line(opt, "}");
michael@0 299 }
michael@0 300 current = next;
michael@0 301 }
michael@0 302
michael@0 303 if (!use_if) {
michael@0 304 line(opt, "}");
michael@0 305 }
michael@0 306
michael@0 307 columns[optimal_column_index] = optimal_column;
michael@0 308
michael@0 309 line(opt, "JSKW_NO_MATCH()");
michael@0 310 }
michael@0 311 }
michael@0 312
michael@0 313 static void
michael@0 314 generate_letter_switch(struct gen_opt *opt,
michael@0 315 unsigned indexes[], unsigned nelem,
michael@0 316 unsigned current_length)
michael@0 317 {
michael@0 318 unsigned *columns;
michael@0 319 unsigned i;
michael@0 320
michael@0 321 columns = (unsigned *) malloc(sizeof(columns[0]) * current_length);
michael@0 322 if (!columns) {
michael@0 323 perror("malloc");
michael@0 324 exit(EXIT_FAILURE);
michael@0 325 }
michael@0 326 for (i = 0; i != current_length; ++i) {
michael@0 327 columns[i] = i;
michael@0 328 }
michael@0 329 generate_letter_switch_r(opt, indexes, nelem, columns, current_length);
michael@0 330 free(columns);
michael@0 331 }
michael@0 332
michael@0 333
michael@0 334 static void
michael@0 335 generate_switch(struct gen_opt *opt)
michael@0 336 {
michael@0 337 unsigned *indexes;
michael@0 338 unsigned nlength;
michael@0 339 unsigned i, current;
michael@0 340 int use_if;
michael@0 341 unsigned nelem;
michael@0 342
michael@0 343 nelem = sizeof(keyword_list)/sizeof(keyword_list[0]);
michael@0 344
michael@0 345 line(opt, "/*");
michael@0 346 line(opt, " * Generating switch for the list of %u entries:", nelem);
michael@0 347 for (i = 0; i != nelem; ++i) {
michael@0 348 line(opt, " * %s", keyword_list[i]);
michael@0 349 }
michael@0 350 line(opt, " */");
michael@0 351
michael@0 352 indexes = (unsigned *) malloc(sizeof(indexes[0]) * nelem);
michael@0 353 if (!indexes) {
michael@0 354 perror("malloc");
michael@0 355 exit(EXIT_FAILURE);
michael@0 356 }
michael@0 357 for (i = 0; i != nelem; ++i)
michael@0 358 indexes[i] = i;
michael@0 359 qsort(indexes, nelem, sizeof(indexes[i]), length_comparator);
michael@0 360 nlength = count_different_lengths(indexes, nelem);
michael@0 361
michael@0 362 use_if = (nlength <= opt->use_if_threshold);
michael@0 363
michael@0 364 if (!use_if)
michael@0 365 line(opt, "switch (JSKW_LENGTH()) {");
michael@0 366
michael@0 367 current = (unsigned)strlen(keyword_list[indexes[0]]);
michael@0 368 for (i = 0; i != nelem;) {
michael@0 369 unsigned same_length_begin = i;
michael@0 370 unsigned next = current;
michael@0 371
michael@0 372 for (++i; i != nelem; ++i) {
michael@0 373 next = (unsigned)strlen(keyword_list[indexes[i]]);
michael@0 374 if (next != current)
michael@0 375 break;
michael@0 376 }
michael@0 377 if (use_if) {
michael@0 378 line(opt, "if (JSKW_LENGTH() == %u) {", current);
michael@0 379 } else {
michael@0 380 line(opt, " case %u:", current);
michael@0 381 }
michael@0 382 ++opt->indent_level;
michael@0 383 generate_letter_switch(opt, indexes + same_length_begin,
michael@0 384 i - same_length_begin,
michael@0 385 current);
michael@0 386 --opt->indent_level;
michael@0 387 if (use_if) {
michael@0 388 line(opt, "}");
michael@0 389 }
michael@0 390 current = next;
michael@0 391 }
michael@0 392 if (!use_if)
michael@0 393 line(opt, "}");
michael@0 394 line(opt, "JSKW_NO_MATCH()");
michael@0 395 free(indexes);
michael@0 396 }
michael@0 397
michael@0 398 int main(int argc, char **argv)
michael@0 399 {
michael@0 400 struct gen_opt opt;
michael@0 401
michael@0 402 if (argc < 2) {
michael@0 403 opt.output = stdout;
michael@0 404 } else {
michael@0 405 opt.output = fopen(argv[1], "w");
michael@0 406 if (!opt.output) {
michael@0 407 perror("fopen");
michael@0 408 exit(EXIT_FAILURE);
michael@0 409 }
michael@0 410 }
michael@0 411 opt.indent_level = 1;
michael@0 412 opt.use_if_threshold = 3;
michael@0 413 opt.char_tail_test_threshold = 4;
michael@0 414
michael@0 415 generate_switch(&opt);
michael@0 416
michael@0 417 if (opt.output != stdout) {
michael@0 418 if (fclose(opt.output)) {
michael@0 419 perror("fclose");
michael@0 420 exit(EXIT_FAILURE);
michael@0 421 }
michael@0 422 }
michael@0 423
michael@0 424 return EXIT_SUCCESS;
michael@0 425 }

mercurial