blob: 16823bbf5f5f3d7efecd5efe01066021da894643 [file] [log] [blame]
Dan Bornsteind12de172010-12-02 15:21:59 -08001# 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
Dan Bornstein973171b2010-12-03 13:01:06 -080015#
Dan Bornsteind12de172010-12-02 15:21:59 -080016# Awk helper script for opcode-gen.
Dan Bornstein973171b2010-12-03 13:01:06 -080017#
18
19#
20# Initialization.
21#
Dan Bornsteind12de172010-12-02 15:21:59 -080022
23BEGIN {
24 MAX_OPCODE = 65535;
Dan Bornstein3c4dc3b2010-12-02 16:05:51 -080025 MAX_PACKED_OPCODE = 511;
Elliott Hughesab35b502012-01-04 15:38:58 -080026 MAX_PACKED_OPCODE = 255; # TODO: Not for long!
Dan Bornsteind12de172010-12-02 15:21:59 -080027 initIndexTypes();
28 initFlags();
29 if (readBytecodes()) exit 1;
30 deriveOpcodeChains();
Dan Bornstein3c4dc3b2010-12-02 16:05:51 -080031 createPackedTables();
Dan Bornsteind12de172010-12-02 15:21:59 -080032 consumeUntil = "";
Dan Bornstein973171b2010-12-03 13:01:06 -080033 emission = "";
Dan Bornsteind12de172010-12-02 15:21:59 -080034}
35
Dan Bornstein973171b2010-12-03 13:01:06 -080036#
37# General control (must appear above directive handlers).
38#
39
40# Clear out the preexisting output within a directive section.
Dan Bornsteind12de172010-12-02 15:21:59 -080041consumeUntil != "" {
42 if (index($0, consumeUntil) != 0) {
43 consumeUntil = "";
Dan Bornstein973171b2010-12-03 13:01:06 -080044 print;
Dan Bornsteind12de172010-12-02 15:21:59 -080045 }
Dan Bornstein973171b2010-12-03 13:01:06 -080046
47 next;
Dan Bornsteind12de172010-12-02 15:21:59 -080048}
49
Dan Bornstein973171b2010-12-03 13:01:06 -080050# Detect directives.
Dan Bornsteina277f142010-12-03 15:11:55 -080051/BEGIN\([a-z-]*\)/ {
52 i = match($0, /BEGIN\([a-z-]*\)/);
Dan Bornstein973171b2010-12-03 13:01:06 -080053 emission = substr($0, i + 6, RLENGTH - 7);
54 consumeUntil = "END(" emission ")";
55 emissionHandled = 0;
Dan Bornstein9dc57d32010-12-03 17:58:01 -080056}
57
58# Most lines just get copied from the source as-is, including the start
59# comment for directives.
60{
Dan Bornsteind12de172010-12-02 15:21:59 -080061 print;
Dan Bornstein973171b2010-12-03 13:01:06 -080062}
63
64#
65# Handlers for all of the directives.
66#
67
68emission == "opcodes" {
69 emissionHandled = 1;
Dan Bornsteind12de172010-12-02 15:21:59 -080070
71 for (i = 0; i <= MAX_OPCODE; i++) {
72 if (isUnused(i) || isOptimized(i)) continue;
73 printf(" public static final int %s = 0x%s;\n",
74 constName[i], hex[i]);
75 }
Dan Bornsteind12de172010-12-02 15:21:59 -080076}
77
Dan Bornstein973171b2010-12-03 13:01:06 -080078emission == "first-opcodes" {
79 emissionHandled = 1;
Dan Bornsteind12de172010-12-02 15:21:59 -080080
81 for (i = 0; i <= MAX_OPCODE; i++) {
82 if (isUnused(i) || isOptimized(i)) continue;
83 if (isFirst[i] == "true") {
Dan Bornstein7ba91292011-01-30 14:05:39 -080084 printf(" // Opcodes.%s\n", constName[i]);
Dan Bornsteind12de172010-12-02 15:21:59 -080085 }
86 }
Dan Bornsteind12de172010-12-02 15:21:59 -080087}
88
Dan Bornstein973171b2010-12-03 13:01:06 -080089emission == "dops" {
90 emissionHandled = 1;
Dan Bornsteind12de172010-12-02 15:21:59 -080091
92 for (i = 0; i <= MAX_OPCODE; i++) {
93 if (isUnused(i) || isOptimized(i)) continue;
94
95 nextOp = nextOpcode[i];
96 nextOp = (nextOp == -1) ? "NO_NEXT" : constName[nextOp];
97
98 printf(" public static final Dop %s =\n" \
Dan Bornstein7ba91292011-01-30 14:05:39 -080099 " new Dop(Opcodes.%s, Opcodes.%s,\n" \
Dan Bornsteina754fbb2011-02-02 11:45:53 -0800100 " Opcodes.%s, Form%s.THE_ONE, %s);\n\n",
Dan Bornsteind12de172010-12-02 15:21:59 -0800101 constName[i], constName[i], family[i], nextOp, format[i],
Dan Bornsteina754fbb2011-02-02 11:45:53 -0800102 hasResult[i]);
Dan Bornsteind12de172010-12-02 15:21:59 -0800103 }
Dan Bornsteind12de172010-12-02 15:21:59 -0800104}
105
Dan Bornstein3c5df372011-01-25 16:39:12 -0800106emission == "opcode-info-defs" {
107 emissionHandled = 1;
108
109 for (i = 0; i <= MAX_OPCODE; i++) {
110 if (isUnused(i) || isOptimized(i)) continue;
111
Dan Bornsteinf67b6af2011-02-02 14:01:52 -0800112 itype = toupper(indexType[i]);
113 gsub(/-/, "_", itype);
Dan Bornstein3c5df372011-01-25 16:39:12 -0800114
115 printf(" public static final Info %s =\n" \
Dan Bornsteina754fbb2011-02-02 11:45:53 -0800116 " new Info(Opcodes.%s, \"%s\",\n" \
Dan Bornsteinf67b6af2011-02-02 14:01:52 -0800117 " InstructionCodec.FORMAT_%s, IndexType.%s);\n\n", \
Dan Bornsteina754fbb2011-02-02 11:45:53 -0800118 constName[i], constName[i], name[i], toupper(format[i]), itype);
Dan Bornstein3c5df372011-01-25 16:39:12 -0800119 }
120}
121
122emission == "dops-init" || emission == "opcode-info-init" {
Dan Bornstein973171b2010-12-03 13:01:06 -0800123 emissionHandled = 1;
Dan Bornsteind12de172010-12-02 15:21:59 -0800124
125 for (i = 0; i <= MAX_OPCODE; i++) {
126 if (isUnused(i) || isOptimized(i)) continue;
127 printf(" set(%s);\n", constName[i]);
128 }
Dan Bornsteind12de172010-12-02 15:21:59 -0800129}
130
Dan Bornstein973171b2010-12-03 13:01:06 -0800131emission == "libcore-opcodes" {
132 emissionHandled = 1;
Dan Bornsteind12de172010-12-02 15:21:59 -0800133
Dan Bornstein3c4dc3b2010-12-02 16:05:51 -0800134 for (i = 0; i <= MAX_OPCODE; i++) {
135 if (isUnused(i) || isOptimized(i)) continue;
Dan Bornstein21f322d2010-12-03 13:16:08 -0800136 printf(" int OP_%-28s = 0x%04x;\n", constName[i], i);
Dan Bornsteind12de172010-12-02 15:21:59 -0800137 }
Dan Bornsteind12de172010-12-02 15:21:59 -0800138}
139
Dan Bornstein973171b2010-12-03 13:01:06 -0800140emission == "libcore-maximum-values" {
141 emissionHandled = 1;
Dan Bornsteind12de172010-12-02 15:21:59 -0800142
Dan Bornstein3c4dc3b2010-12-02 16:05:51 -0800143 printf(" MAXIMUM_VALUE = %d;\n", MAX_OPCODE);
144 printf(" MAXIMUM_PACKED_VALUE = %d;\n", MAX_PACKED_OPCODE);
Dan Bornsteind12de172010-12-02 15:21:59 -0800145}
146
Aart Bik1a650522015-07-08 21:20:41 +0000147emission == "libdex-maximum-values" {
148 emissionHandled = 1;
149
150 printf("#define kMaxOpcodeValue 0x%x\n", MAX_OPCODE);
151 printf("#define kNumPackedOpcodes 0x%x\n", MAX_PACKED_OPCODE + 1);
152}
153
154emission == "libdex-opcode-enum" {
155 emissionHandled = 1;
156
157 for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
158 printf(" OP_%-28s = 0x%02x,\n", packedConstName[i], i);
159 }
160}
161
162emission == "libdex-goto-table" {
163 emissionHandled = 1;
164
165 for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
166 content = sprintf(" H(OP_%s),", packedConstName[i]);
167 printf("%-78s\\\n", content);
168 }
169}
170
171emission == "libdex-opcode-names" {
172 emissionHandled = 1;
173
174 for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
175 printf(" \"%s\",\n", packedName[i]);
176 }
177}
178
179emission == "libdex-widths" {
180 emissionHandled = 1;
181
182 col = 1;
183 for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
184 value = sprintf("%d,", packedWidth[i]);
185 col = colPrint(value, (i == MAX_PACKED_OPCODE), col, 16, 2, " ");
186 }
187}
188
189emission == "libdex-flags" {
190 emissionHandled = 1;
191
192 for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
193 value = flagsToC(packedFlags[i]);
194 printf(" %s,\n", value);
195 }
196}
197
198emission == "libdex-formats" {
199 emissionHandled = 1;
200
201 col = 1;
202 for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
203 value = sprintf("kFmt%s,", packedFormat[i]);
204 col = colPrint(value, (i == MAX_PACKED_OPCODE), col, 7, 9, " ");
205 }
206}
207
208emission == "libdex-index-types" {
209 emissionHandled = 1;
210
211 col = 1;
212 for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
213 value = sprintf("%s,", indexTypeValues[packedIndexType[i]]);
214 col = colPrint(value, (i == MAX_PACKED_OPCODE), col, 3, 19, " ");
215 }
216}
217
Dan Bornstein9dc57d32010-12-03 17:58:01 -0800218# Handle the end of directive processing (must appear after the directive
219# clauses).
Dan Bornstein973171b2010-12-03 13:01:06 -0800220emission != "" {
221 if (!emissionHandled) {
222 printf("WARNING: unknown tag \"%s\"\n", emission) >"/dev/stderr";
223 consumeUntil = "";
224 }
225
226 emission = "";
Dan Bornsteind12de172010-12-02 15:21:59 -0800227}
228
Dan Bornstein973171b2010-12-03 13:01:06 -0800229#
230# Helper functions.
231#
232
Dan Bornsteind12de172010-12-02 15:21:59 -0800233# Helper to print out an element in a multi-column fashion. It returns
234# the (one-based) column number that the next element will be printed
235# in.
236function colPrint(value, isLast, col, numCols, colWidth, linePrefix) {
237 isLast = (isLast || (col == numCols));
238 printf("%s%-*s%s",
239 (col == 1) ? linePrefix : " ",
240 isLast ? 1 : colWidth, value,
241 isLast ? "\n" : "");
242
243 return (col % numCols) + 1;
244}
245
246# Read the bytecode description file.
247function readBytecodes(i, parts, line, cmd, status, count) {
248 # locals: parts, line, cmd, status, count
249 for (;;) {
250 # Read a line.
251 status = getline line <bytecodeFile;
252 if (status == 0) break;
253 if (status < 0) {
254 print "trouble reading bytecode file";
255 exit 1;
256 }
257
258 # Clean up the line and extract the command.
259 gsub(/ */, " ", line);
260 sub(/ *#.*$/, "", line);
261 sub(/ $/, "", line);
262 sub(/^ /, "", line);
263 count = split(line, parts);
264 if (count == 0) continue; # Blank or comment line.
265 cmd = parts[1];
266 sub(/^[a-z][a-z]* */, "", line); # Remove the command from line.
267
268 if (cmd == "op") {
269 status = defineOpcode(line);
270 } else if (cmd == "format") {
271 status = defineFormat(line);
272 } else {
273 status = -1;
274 }
275
276 if (status != 0) {
Dan Bornstein973171b2010-12-03 13:01:06 -0800277 printf("syntax error on line: %s\n", line) >"/dev/stderr";
Dan Bornsteind12de172010-12-02 15:21:59 -0800278 return 1;
279 }
280 }
281
282 return 0;
283}
284
285# Define an opcode.
286function defineOpcode(line, count, parts, idx) {
287 # locals: count, parts, idx
288 count = split(line, parts);
289 if (count != 6) return -1;
290 idx = parseHex(parts[1]);
291 if (idx < 0) return -1;
292
293 # Extract directly specified values from the line.
294 hex[idx] = parts[1];
295 name[idx] = parts[2];
296 format[idx] = parts[3];
297 hasResult[idx] = (parts[4] == "n") ? "false" : "true";
298 indexType[idx] = parts[5];
299 flags[idx] = parts[6];
300
301 # Calculate derived values.
302
303 constName[idx] = toupper(name[idx]);
Dan Bornstein9dc57d32010-12-03 17:58:01 -0800304 gsub("[/-]", "_", constName[idx]); # Dash and slash become underscore.
Dan Bornsteind12de172010-12-02 15:21:59 -0800305 gsub("[+^]", "", constName[idx]); # Plus and caret are removed.
306 split(name[idx], parts, "/");
307
308 family[idx] = toupper(parts[1]);
309 gsub("-", "_", family[idx]); # Dash becomes underscore.
310 gsub("[+^]", "", family[idx]); # Plus and caret are removed.
311
312 split(format[idx], parts, ""); # Width is the first format char.
313 width[idx] = parts[1];
314
315 # This association is used when computing "next" opcodes.
316 familyFormat[family[idx],format[idx]] = idx;
317
318 # Verify values.
319
320 if (nextFormat[format[idx]] == "") {
Dan Bornstein973171b2010-12-03 13:01:06 -0800321 printf("unknown format: %s\n", format[idx]) >"/dev/stderr";
Dan Bornsteind12de172010-12-02 15:21:59 -0800322 return 1;
323 }
324
325 if (indexTypeValues[indexType[idx]] == "") {
Dan Bornstein973171b2010-12-03 13:01:06 -0800326 printf("unknown index type: %s\n", indexType[idx]) >"/dev/stderr";
Dan Bornsteind12de172010-12-02 15:21:59 -0800327 return 1;
328 }
329
330 if (flagsToC(flags[idx]) == "") {
Dan Bornstein973171b2010-12-03 13:01:06 -0800331 printf("bogus flags: %s\n", flags[idx]) >"/dev/stderr";
Dan Bornsteind12de172010-12-02 15:21:59 -0800332 return 1;
333 }
334
335 return 0;
336}
337
338# Define a format family.
339function defineFormat(line, count, parts, i) {
340 # locals: count, parts, i
341 count = split(line, parts);
342 if (count < 1) return -1;
343 formats[parts[1]] = line;
344
345 parts[count + 1] = "none";
346 for (i = 1; i <= count; i++) {
347 nextFormat[parts[i]] = parts[i + 1];
348 }
349
350 return 0;
351}
352
353# Produce the nextOpcode and isFirst arrays. The former indicates, for
354# each opcode, which one should be tried next when doing instruction
355# fitting. The latter indicates which opcodes are at the head of an
356# instruction fitting chain.
357function deriveOpcodeChains(i, op) {
358 # locals: i, op
359
360 for (i = 0; i <= MAX_OPCODE; i++) {
361 if (isUnused(i)) continue;
362 isFirst[i] = "true";
363 }
364
365 for (i = 0; i <= MAX_OPCODE; i++) {
366 if (isUnused(i)) continue;
367 op = findNextOpcode(i);
368 nextOpcode[i] = op;
369 if (op != -1) {
370 isFirst[op] = "false";
371 }
372 }
373}
374
375# Given an opcode by index, find the next opcode in the same family
376# (that is, with the same base name) to try when matching instructions
377# to opcodes. This simply walks the nextFormat chain looking for a
378# match. This returns the index of the matching opcode or -1 if there
379# is none.
380function findNextOpcode(idx, fam, fmt, result) {
381 # locals: fam, fmt, result
382 fam = family[idx];
383 fmt = format[idx];
384
385 # Not every opcode has a version with every possible format, so
386 # we have to iterate down the chain until we find one or run out of
387 # formats to try.
388 for (fmt = nextFormat[format[idx]]; fmt != "none"; fmt = nextFormat[fmt]) {
389 result = familyFormat[fam,fmt];
390 if (result != "") {
391 return result;
392 }
393 }
394
395 return -1;
396}
397
Dan Bornstein3c4dc3b2010-12-02 16:05:51 -0800398# Construct the tables of info indexed by packed opcode. The packed opcode
399# values are in the range 0-0x1ff, whereas the unpacked opcodes sparsely
400# span the range 0-0xffff.
401function createPackedTables(i, op) {
402 # locals: i, op
403 for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
404 op = unpackOpcode(i);
Elliott Hughesab35b502012-01-04 15:38:58 -0800405 if (isUnused(op)) {
Dan Bornstein3c4dc3b2010-12-02 16:05:51 -0800406 packedName[i] = unusedName(op);
407 packedConstName[i] = unusedConstName(op);
408 packedFormat[i] = "00x";
409 packedFlags[i] = 0;
410 packedWidth[i] = 0;
411 packedIndexType[i] = "unknown";
412 } else {
413 packedName[i] = name[op];
414 packedConstName[i] = constName[op];
415 packedFormat[i] = format[op];
416 packedFlags[i] = flags[op];
417 packedWidth[i] = width[op];
418 packedIndexType[i] = indexType[op];
419 }
420 }
421}
422
423# Given a packed opcode, returns the raw (unpacked) opcode value.
424function unpackOpcode(idx) {
Aart Bik1a650522015-07-08 21:20:41 +0000425 # Note: This must be the inverse of the corresponding code in
426 # libdex/DexOpcodes.h.
Dan Bornstein3c4dc3b2010-12-02 16:05:51 -0800427 if (idx <= 255) {
428 return idx;
429 } else {
Dan Bornstein21f322d2010-12-03 13:16:08 -0800430 idx -= 256;
Dan Bornstein3c4dc3b2010-12-02 16:05:51 -0800431 return (idx * 256) + 255;
432 }
433}
434
435# Returns the "unused" name of the given opcode (by index).
436# That is, this is the human-oriented name to use for an opcode
437# definition in cases
438# where the opcode isn't used.
439function unusedName(idx) {
440 if (idx <= 255) {
441 return sprintf("unused-%02x", idx);
442 } else {
443 return sprintf("unused-%04x", idx);
444 }
445}
446
447# Returns the "unused" constant name of the given opcode (by index).
448# That is, this is the name to use for a constant definition in cases
449# where the opcode isn't used.
450function unusedConstName(idx) {
451 if (idx <= 255) {
452 return toupper(sprintf("UNUSED_%02x", idx));
453 } else {
454 return toupper(sprintf("UNUSED_%04x", idx));
455 }
456}
457
Dan Bornsteind12de172010-12-02 15:21:59 -0800458# Convert a hex value to an int.
459function parseHex(hex, result, chars, count, c, i) {
460 # locals: result, chars, count, c, i
461 hex = tolower(hex);
462 count = split(hex, chars, "");
463 result = 0;
464 for (i = 1; i <= count; i++) {
465 c = index("0123456789abcdef", chars[i]);
466 if (c == 0) {
Dan Bornstein973171b2010-12-03 13:01:06 -0800467 printf("bogus hex value: %s\n", hex) >"/dev/stderr";
Dan Bornsteind12de172010-12-02 15:21:59 -0800468 return -1;
469 }
470 result = (result * 16) + c - 1;
471 }
472 return result;
473}
474
475# Initialize the indexTypes data.
476function initIndexTypes() {
Orion Hodsonab9e85c2017-02-01 10:42:01 +0000477 indexTypeValues["unknown"] = "kIndexUnknown";
478 indexTypeValues["none"] = "kIndexNone";
479 indexTypeValues["varies"] = "kIndexVaries";
480 indexTypeValues["type-ref"] = "kIndexTypeRef";
481 indexTypeValues["string-ref"] = "kIndexStringRef";
482 indexTypeValues["method-ref"] = "kIndexMethodRef";
483 indexTypeValues["field-ref"] = "kIndexFieldRef";
484 indexTypeValues["inline-method"] = "kIndexInlineMethod";
485 indexTypeValues["vtable-offset"] = "kIndexVtableOffset";
486 indexTypeValues["field-offset"] = "kIndexFieldOffset";
487 indexTypeValues["method-and-proto-ref"] = "kIndexMethodAndProtoRef";
Orion Hodson766a6782017-09-21 15:27:51 +0100488 indexTypeValues["call-site-ref"] = "kIndexCallSiteRef";
489 indexTypeValues["method-handle-ref"] = "kIndexMethodHandleRef";
490 indexTypeValues["proto-ref"] = "kIndexProtoRef";
Dan Bornsteind12de172010-12-02 15:21:59 -0800491}
492
493# Initialize the flags data.
494function initFlags() {
495 flagValues["branch"] = "kInstrCanBranch";
496 flagValues["continue"] = "kInstrCanContinue";
497 flagValues["switch"] = "kInstrCanSwitch";
498 flagValues["throw"] = "kInstrCanThrow";
499 flagValues["return"] = "kInstrCanReturn";
500 flagValues["invoke"] = "kInstrInvoke";
501 flagValues["optimized"] = "0"; # Not represented in C output
502 flagValues["0"] = "0";
503}
504
505# Translate the given flags into the equivalent C expression. Returns
506# "" on error.
507function flagsToC(f, parts, result, i) {
508 # locals: parts, result, i
509 count = split(f, parts, /\|/); # Split input at pipe characters.
510 result = "0";
511
512 for (i = 1; i <= count; i++) {
513 f = flagValues[parts[i]];
514 if (f == "") {
Dan Bornstein973171b2010-12-03 13:01:06 -0800515 printf("bogus flag: %s\n", f) >"/dev/stderr";
Dan Bornsteind12de172010-12-02 15:21:59 -0800516 return ""; # Bogus flag name.
517 } else if (f == "0") {
518 # Nothing to append for this case.
519 } else if (result == "0") {
520 result = f;
521 } else {
522 result = result "|" f;
523 }
524 }
525
526 return result;
527}
528
Dan Bornsteind12de172010-12-02 15:21:59 -0800529# Returns true if the given opcode (by index) is an "optimized" opcode.
530function isOptimized(idx, parts, f) {
531 # locals: parts, f
532 split(flags[idx], parts, /\|/); # Split flags[idx] at pipes.
533 for (f in parts) {
534 if (parts[f] == "optimized") return 1;
535 }
536 return 0;
537}
538
539# Returns true if there is no definition for the given opcode (by index).
540function isUnused(idx) {
541 return (name[idx] == "");
542}