opcode-gen.awk revision 3c4dc3bc03f87e181c06f633c4c085341faeee92
1# Copyright (C) 2007 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15# Awk helper script for opcode-gen. 16 17BEGIN { 18 MAX_OPCODE = 65535; 19 MAX_PACKED_OPCODE = 511; 20 MAX_PACKED_OPCODE = 255; # TODO: Not for long! 21 initIndexTypes(); 22 initFlags(); 23 if (readBytecodes()) exit 1; 24 deriveOpcodeChains(); 25 createPackedTables(); 26 consumeUntil = ""; 27} 28 29consumeUntil != "" { 30 if (index($0, consumeUntil) != 0) { 31 consumeUntil = ""; 32 } else { 33 next; 34 } 35} 36 37/BEGIN\(opcodes\)/ { 38 consumeUntil = "END(opcodes)"; 39 print; 40 41 for (i = 0; i <= MAX_OPCODE; i++) { 42 if (isUnused(i) || isOptimized(i)) continue; 43 printf(" public static final int %s = 0x%s;\n", 44 constName[i], hex[i]); 45 } 46 47 next; 48} 49 50/BEGIN\(first-opcodes\)/ { 51 consumeUntil = "END(first-opcodes)"; 52 print; 53 54 for (i = 0; i <= MAX_OPCODE; i++) { 55 if (isUnused(i) || isOptimized(i)) continue; 56 if (isFirst[i] == "true") { 57 printf(" // DalvOps.%s\n", constName[i]); 58 } 59 } 60 61 next; 62} 63 64/BEGIN\(dops\)/ { 65 consumeUntil = "END(dops)"; 66 print; 67 68 for (i = 0; i <= MAX_OPCODE; i++) { 69 if (isUnused(i) || isOptimized(i)) continue; 70 71 nextOp = nextOpcode[i]; 72 nextOp = (nextOp == -1) ? "NO_NEXT" : constName[nextOp]; 73 74 printf(" public static final Dop %s =\n" \ 75 " new Dop(DalvOps.%s, DalvOps.%s,\n" \ 76 " DalvOps.%s, Form%s.THE_ONE, %s,\n" \ 77 " \"%s\");\n\n", 78 constName[i], constName[i], family[i], nextOp, format[i], 79 hasResult[i], name[i]); 80 } 81 82 next; 83} 84 85/BEGIN\(dops-init\)/ { 86 consumeUntil = "END(dops-init)"; 87 print; 88 89 for (i = 0; i <= MAX_OPCODE; i++) { 90 if (isUnused(i) || isOptimized(i)) continue; 91 printf(" set(%s);\n", constName[i]); 92 } 93 94 next; 95} 96 97/BEGIN\(libcore-opcodes\)/ { 98 consumeUntil = "END(libcore-opcodes)"; 99 print; 100 101 for (i = 0; i <= MAX_OPCODE; i++) { 102 if (isUnused(i) || isOptimized(i)) continue; 103 printf(" int OP_%-28s = 0x%02x;\n", constName[i], i); 104 } 105 106 next; 107} 108 109/BEGIN\(libcore-maximum-values\)/ { 110 consumeUntil = "END(libcore-maximum-values)"; 111 print; 112 113 printf(" MAXIMUM_VALUE = %d;\n", MAX_OPCODE); 114 printf(" MAXIMUM_PACKED_VALUE = %d;\n", MAX_PACKED_OPCODE); 115 116 next; 117} 118 119/BEGIN\(libdex-opcode-enum\)/ { 120 consumeUntil = "END(libdex-opcode-enum)"; 121 print; 122 123 for (i = 0; i <= MAX_PACKED_OPCODE; i++) { 124 printf(" OP_%-28s = 0x%02x,\n", packedConstName[i], i); 125 } 126 127 next; 128} 129 130/BEGIN\(libdex-goto-table\)/ { 131 consumeUntil = "END(libdex-goto-table)"; 132 print; 133 134 for (i = 0; i <= MAX_PACKED_OPCODE; i++) { 135 content = sprintf(" H(OP_%s),", packedConstName[i]); 136 printf("%-78s\\\n", content); 137 } 138 139 next; 140} 141 142/BEGIN\(libdex-opcode-names\)/ { 143 consumeUntil = "END(libdex-opcode-names)"; 144 print; 145 146 for (i = 0; i <= MAX_PACKED_OPCODE; i++) { 147 printf(" \"%s\",\n", packedName[i]); 148 } 149 150 next; 151} 152 153/BEGIN\(libdex-widths\)/ { 154 consumeUntil = "END(libdex-widths)"; 155 print; 156 157 col = 1; 158 for (i = 0; i <= MAX_PACKED_OPCODE; i++) { 159 value = sprintf("%d,", packedWidth[i]); 160 col = colPrint(value, (i == MAX_PACKED_OPCODE), col, 16, 2, " "); 161 } 162 163 next; 164} 165 166/BEGIN\(libdex-flags\)/ { 167 consumeUntil = "END(libdex-flags)"; 168 print; 169 170 for (i = 0; i <= MAX_PACKED_OPCODE; i++) { 171 value = flagsToC(packedFlags[i]); 172 printf(" %s,\n", value); 173 } 174 175 next; 176} 177 178/BEGIN\(libdex-formats\)/ { 179 consumeUntil = "END(libdex-formats)"; 180 print; 181 182 col = 1; 183 for (i = 0; i <= MAX_PACKED_OPCODE; i++) { 184 value = sprintf("kFmt%s,", packedFormat[i]); 185 col = colPrint(value, (i == MAX_PACKED_OPCODE), col, 7, 9, " "); 186 } 187 188 next; 189} 190 191/BEGIN\(libdex-index-types\)/ { 192 consumeUntil = "END(libdex-index-types)"; 193 print; 194 195 col = 1; 196 for (i = 0; i <= MAX_PACKED_OPCODE; i++) { 197 value = sprintf("%s,", indexTypeValues[packedIndexType[i]]); 198 col = colPrint(value, (i == MAX_PACKED_OPCODE), col, 3, 19, " "); 199 } 200 201 next; 202} 203 204{ print; } 205 206# Helper to print out an element in a multi-column fashion. It returns 207# the (one-based) column number that the next element will be printed 208# in. 209function colPrint(value, isLast, col, numCols, colWidth, linePrefix) { 210 isLast = (isLast || (col == numCols)); 211 printf("%s%-*s%s", 212 (col == 1) ? linePrefix : " ", 213 isLast ? 1 : colWidth, value, 214 isLast ? "\n" : ""); 215 216 return (col % numCols) + 1; 217} 218 219# Read the bytecode description file. 220function readBytecodes(i, parts, line, cmd, status, count) { 221 # locals: parts, line, cmd, status, count 222 for (;;) { 223 # Read a line. 224 status = getline line <bytecodeFile; 225 if (status == 0) break; 226 if (status < 0) { 227 print "trouble reading bytecode file"; 228 exit 1; 229 } 230 231 # Clean up the line and extract the command. 232 gsub(/ */, " ", line); 233 sub(/ *#.*$/, "", line); 234 sub(/ $/, "", line); 235 sub(/^ /, "", line); 236 count = split(line, parts); 237 if (count == 0) continue; # Blank or comment line. 238 cmd = parts[1]; 239 sub(/^[a-z][a-z]* */, "", line); # Remove the command from line. 240 241 if (cmd == "op") { 242 status = defineOpcode(line); 243 } else if (cmd == "format") { 244 status = defineFormat(line); 245 } else { 246 status = -1; 247 } 248 249 if (status != 0) { 250 printf("syntax error on line: %s\n", line); 251 return 1; 252 } 253 } 254 255 return 0; 256} 257 258# Define an opcode. 259function defineOpcode(line, count, parts, idx) { 260 # locals: count, parts, idx 261 count = split(line, parts); 262 if (count != 6) return -1; 263 idx = parseHex(parts[1]); 264 if (idx < 0) return -1; 265 266 # Extract directly specified values from the line. 267 hex[idx] = parts[1]; 268 name[idx] = parts[2]; 269 format[idx] = parts[3]; 270 hasResult[idx] = (parts[4] == "n") ? "false" : "true"; 271 indexType[idx] = parts[5]; 272 flags[idx] = parts[6]; 273 274 # Calculate derived values. 275 276 constName[idx] = toupper(name[idx]); 277 gsub("[---/]", "_", constName[idx]); # Dash and slash become underscore. 278 gsub("[+^]", "", constName[idx]); # Plus and caret are removed. 279 split(name[idx], parts, "/"); 280 281 family[idx] = toupper(parts[1]); 282 gsub("-", "_", family[idx]); # Dash becomes underscore. 283 gsub("[+^]", "", family[idx]); # Plus and caret are removed. 284 285 split(format[idx], parts, ""); # Width is the first format char. 286 width[idx] = parts[1]; 287 288 # This association is used when computing "next" opcodes. 289 familyFormat[family[idx],format[idx]] = idx; 290 291 # Verify values. 292 293 if (nextFormat[format[idx]] == "") { 294 printf("unknown format: %s\n", format[idx]); 295 return 1; 296 } 297 298 if (indexTypeValues[indexType[idx]] == "") { 299 printf("unknown index type: %s\n", indexType[idx]); 300 return 1; 301 } 302 303 if (flagsToC(flags[idx]) == "") { 304 printf("bogus flags: %s\n", flags[idx]); 305 return 1; 306 } 307 308 return 0; 309} 310 311# Define a format family. 312function defineFormat(line, count, parts, i) { 313 # locals: count, parts, i 314 count = split(line, parts); 315 if (count < 1) return -1; 316 formats[parts[1]] = line; 317 318 parts[count + 1] = "none"; 319 for (i = 1; i <= count; i++) { 320 nextFormat[parts[i]] = parts[i + 1]; 321 } 322 323 return 0; 324} 325 326# Produce the nextOpcode and isFirst arrays. The former indicates, for 327# each opcode, which one should be tried next when doing instruction 328# fitting. The latter indicates which opcodes are at the head of an 329# instruction fitting chain. 330function deriveOpcodeChains(i, op) { 331 # locals: i, op 332 333 for (i = 0; i <= MAX_OPCODE; i++) { 334 if (isUnused(i)) continue; 335 isFirst[i] = "true"; 336 } 337 338 for (i = 0; i <= MAX_OPCODE; i++) { 339 if (isUnused(i)) continue; 340 op = findNextOpcode(i); 341 nextOpcode[i] = op; 342 if (op != -1) { 343 isFirst[op] = "false"; 344 } 345 } 346} 347 348# Given an opcode by index, find the next opcode in the same family 349# (that is, with the same base name) to try when matching instructions 350# to opcodes. This simply walks the nextFormat chain looking for a 351# match. This returns the index of the matching opcode or -1 if there 352# is none. 353function findNextOpcode(idx, fam, fmt, result) { 354 # locals: fam, fmt, result 355 fam = family[idx]; 356 fmt = format[idx]; 357 358 # Not every opcode has a version with every possible format, so 359 # we have to iterate down the chain until we find one or run out of 360 # formats to try. 361 for (fmt = nextFormat[format[idx]]; fmt != "none"; fmt = nextFormat[fmt]) { 362 result = familyFormat[fam,fmt]; 363 if (result != "") { 364 return result; 365 } 366 } 367 368 return -1; 369} 370 371# Construct the tables of info indexed by packed opcode. The packed opcode 372# values are in the range 0-0x1ff, whereas the unpacked opcodes sparsely 373# span the range 0-0xffff. 374function createPackedTables(i, op) { 375 # locals: i, op 376 for (i = 0; i <= MAX_PACKED_OPCODE; i++) { 377 op = unpackOpcode(i); 378 if (i == 255) { 379 # Special case: This is the low-opcode slot for a would-be 380 # extended opcode dispatch implementation. 381 packedName[i] = "dispatch-ff"; 382 packedConstName[i] = "DISPATCH_FF"; 383 packedFormat[i] = "00x"; 384 packedFlags[i] = 0; 385 packedWidth[i] = 0; 386 packedIndexType[i] = "unknown"; 387 } else if (isUnused(op)) { 388 packedName[i] = unusedName(op); 389 packedConstName[i] = unusedConstName(op); 390 packedFormat[i] = "00x"; 391 packedFlags[i] = 0; 392 packedWidth[i] = 0; 393 packedIndexType[i] = "unknown"; 394 } else { 395 packedName[i] = name[op]; 396 packedConstName[i] = constName[op]; 397 packedFormat[i] = format[op]; 398 packedFlags[i] = flags[op]; 399 packedWidth[i] = width[op]; 400 packedIndexType[i] = indexType[op]; 401 } 402 } 403} 404 405# Given a packed opcode, returns the raw (unpacked) opcode value. 406function unpackOpcode(idx) { 407 # Note: This must be the inverse of the corresponding code in 408 # libdex/DexOpcodes.h. 409 if (idx <= 255) { 410 return idx; 411 } else { 412 return (idx * 256) + 255; 413 } 414} 415 416# Returns the "unused" name of the given opcode (by index). 417# That is, this is the human-oriented name to use for an opcode 418# definition in cases 419# where the opcode isn't used. 420function unusedName(idx) { 421 if (idx <= 255) { 422 return sprintf("unused-%02x", idx); 423 } else { 424 return sprintf("unused-%04x", idx); 425 } 426} 427 428# Returns the "unused" constant name of the given opcode (by index). 429# That is, this is the name to use for a constant definition in cases 430# where the opcode isn't used. 431function unusedConstName(idx) { 432 if (idx <= 255) { 433 return toupper(sprintf("UNUSED_%02x", idx)); 434 } else { 435 return toupper(sprintf("UNUSED_%04x", idx)); 436 } 437} 438 439# Convert a hex value to an int. 440function parseHex(hex, result, chars, count, c, i) { 441 # locals: result, chars, count, c, i 442 hex = tolower(hex); 443 count = split(hex, chars, ""); 444 result = 0; 445 for (i = 1; i <= count; i++) { 446 c = index("0123456789abcdef", chars[i]); 447 if (c == 0) { 448 printf("bogus hex value: %s\n", hex); 449 return -1; 450 } 451 result = (result * 16) + c - 1; 452 } 453 return result; 454} 455 456# Initialize the indexTypes data. 457function initIndexTypes() { 458 indexTypeValues["unknown"] = "kIndexUnknown"; 459 indexTypeValues["none"] = "kIndexNone"; 460 indexTypeValues["varies"] = "kIndexVaries"; 461 indexTypeValues["type-ref"] = "kIndexTypeRef"; 462 indexTypeValues["string-ref"] = "kIndexStringRef"; 463 indexTypeValues["method-ref"] = "kIndexMethodRef"; 464 indexTypeValues["field-ref"] = "kIndexFieldRef"; 465 indexTypeValues["inline-method"] = "kIndexInlineMethod"; 466 indexTypeValues["vtable-offset"] = "kIndexVtableOffset"; 467 indexTypeValues["field-offset"] = "kIndexFieldOffset"; 468} 469 470# Initialize the flags data. 471function initFlags() { 472 flagValues["branch"] = "kInstrCanBranch"; 473 flagValues["continue"] = "kInstrCanContinue"; 474 flagValues["switch"] = "kInstrCanSwitch"; 475 flagValues["throw"] = "kInstrCanThrow"; 476 flagValues["return"] = "kInstrCanReturn"; 477 flagValues["invoke"] = "kInstrInvoke"; 478 flagValues["optimized"] = "0"; # Not represented in C output 479 flagValues["0"] = "0"; 480} 481 482# Translate the given flags into the equivalent C expression. Returns 483# "" on error. 484function flagsToC(f, parts, result, i) { 485 # locals: parts, result, i 486 count = split(f, parts, /\|/); # Split input at pipe characters. 487 result = "0"; 488 489 for (i = 1; i <= count; i++) { 490 f = flagValues[parts[i]]; 491 if (f == "") { 492 printf("bogus flag: %s\n", f); 493 return ""; # Bogus flag name. 494 } else if (f == "0") { 495 # Nothing to append for this case. 496 } else if (result == "0") { 497 result = f; 498 } else { 499 result = result "|" f; 500 } 501 } 502 503 return result; 504} 505 506# Returns true if the given opcode (by index) is an "optimized" opcode. 507function isOptimized(idx, parts, f) { 508 # locals: parts, f 509 split(flags[idx], parts, /\|/); # Split flags[idx] at pipes. 510 for (f in parts) { 511 if (parts[f] == "optimized") return 1; 512 } 513 return 0; 514} 515 516# Returns true if there is no definition for the given opcode (by index). 517function isUnused(idx) { 518 return (name[idx] == ""); 519} 520