|
| 1 | +/** Extract op codes for twg2.jbcm.Opcodes from oracle's JVM spec html page. |
| 2 | + * run the following javascript code in the console tools of the page to extract opcodes. |
| 3 | + * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html |
| 4 | + * @author TeamworkGuy2 |
| 5 | + * @since 2020-06-11 |
| 6 | + */ |
| 7 | + |
| 8 | +function texts(root, idx, selector, num) { |
| 9 | + var elems = root.querySelectorAll(selector); |
| 10 | + if(num > 0 && num != elems.length) { |
| 11 | + throw new Error("expected " + num + " but found " + elems.length + " elements: " + selector + " (at " + idx + ")"); |
| 12 | + } |
| 13 | + var res = Array.prototype.reduce.call(elems, function (ary, elem) { |
| 14 | + ary.push(elem.textContent.trim()); |
| 15 | + return ary; |
| 16 | + }, []); |
| 17 | + return res; |
| 18 | +} |
| 19 | +var baseUrl = "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html"; |
| 20 | +var sections = Array.prototype.slice.call(document.querySelectorAll(".section-execution")) |
| 21 | + |
| 22 | +res = []; |
| 23 | +sections.forEach((el, idx) => { |
| 24 | + var operation = texts(el, idx, ".section[title='Operation'] p.norm", 1)[0].split("\n").join(" ").replace(/\s+/g, " ").trim(); |
| 25 | + var formats = texts(el, idx, ".section .literallayout", -1).map(s => s.split("\n").map(t => t.trim())); |
| 26 | + var operandStack = texts(el, idx, ".section[title='Operand Stack'] p.norm", -1).join("\n").split(/[→\n]/).map(s => s.trim()) |
| 27 | + .filter(s => s.length > 0 && (s.startsWith("...") || s.startsWith("[") || s.startsWith("Form ") || s.startsWith("Same as ")/*wide*/ || s === "No change"/*goto, goto_w, iinc, nop, ret, breakpoint*/ || s.indexOf(" ") === -1/*athrow*/)); |
| 28 | + var description = texts(el, idx, ".norm-dynamic", -1).join(" ").replace(/\s+/g, " ").trim(); |
| 29 | + var forms = texts(el, idx, ".section[title='Forms'] p.norm", -1).filter(s => s.length > 0); |
| 30 | + var hashLink = el.querySelector(".titlepage h3.title a").getAttribute("name"); |
| 31 | + for(var j = 0; j < forms.length; j++) { |
| 32 | + var opCode = parseInt(forms[j].split(" = ")[1].split(" (")[0]); |
| 33 | + var name = forms[j].split(" = ")[0]; |
| 34 | + res.push({ name: name, opCode: opCode, operation: operation, formats: formats, forms: forms, operandStack: operandStack, description: description, hashLink: hashLink }); |
| 35 | + } |
| 36 | +}); |
| 37 | +res.push({ name: "breakpoint", opCode: 202, operation: "reserved for debuggers", formats: [["breakpoint"]], forms: ["breakpoint"], operandStack: ["No change"], description: "Intended to be used by debuggers to implement breakpoints" }); |
| 38 | +res.push({ name: "impdep1", opCode: 254, operation: "reserved opcode", formats: [["impdep1"]], forms: ["impdep1"], operandStack: [""], description: "These instructions are intended to provide \"back doors\" or traps to implementation-specific functionality implemented in software and hardware, respectively" }); |
| 39 | +res.push({ name: "impdep2", opCode: 255, operation: "reserved opcode", formats: [["impdep2"]], forms: ["impdep2"], operandStack: [""], description: "These instructions are intended to provide \"back doors\" or traps to implementation-specific functionality implemented in software and hardware, respectively" }); |
| 40 | +res = res.sort((a,b) => a.opCode - b.opCode).filter(s => !isNaN(s.opCode)/*mnemonic example at top of page*/); |
| 41 | +res.push({ name: "undefined", opCode: -1, operation: "", formats: [[]], forms: [], operandStack: [""], description: "" }); |
| 42 | + |
| 43 | +res.map((rr, idx, ary) => { |
| 44 | + var opStackOffset = rr.operandStack[0].startsWith("Form ") ? 1 : 0; |
| 45 | + var stackPopCount = rr.operandStack[opStackOffset].split(", ").length - 1; |
| 46 | + var stackPushCount = rr.operandStack.length > opStackOffset + 1 ? rr.operandStack[opStackOffset + 1].split(", ").length - 1 : 0; |
| 47 | + var operandCount = rr.description.indexOf("variable-length instruction") > -1 || rr.name === "wide" ? "Const.UNPREDICTABLE" : (rr.operation.startsWith("reserved") ? "Const.RESERVED" : rr.formats[0].length - 1); |
| 48 | + var isCondition = rr.name.startsWith("if"); |
| 49 | + var isJump = rr.operation.startsWith("Branch ") || rr.name === "jsr" || rr.name === "jsr_w"; |
| 50 | + var isCpIndex = rr.description.indexOf("index into the run-time constant pool of the current class") > -1; |
| 51 | + var isStackManipulate = rr.name.startsWith("dup") || rr.name === "swap"; |
| 52 | + var isVariableStackPop = rr.operandStack[opStackOffset].indexOf("[arg") > -1; |
| 53 | + var types; |
| 54 | + var opUtils; |
| 55 | + return "\t/* " + String(rr.opCode).padStart(2, ' ') + " " + ("0x" + rr.opCode.toString(16).toUpperCase()).padStart(4, ' ') + " */" + |
| 56 | + rr.name.toUpperCase().padEnd(16, ' ') + |
| 57 | + "(" + rr.opCode + ", " + operandCount + ", " + |
| 58 | + ((types = [ |
| 59 | + (isStackManipulate ? "Type.STACK_MANIPULATE" : null), |
| 60 | + (isVariableStackPop ? "Type.POP_UNPREDICTABLE" : null), |
| 61 | + (stackPopCount > 0 && !isStackManipulate && !isVariableStackPop ? "Type.POP" + stackPopCount : null), |
| 62 | + (stackPushCount > 0 && !isStackManipulate ? "Type.PUSH" + stackPushCount : null), |
| 63 | + (rr.name.indexOf("load") === 1 ? "Type.VAR_LOAD" : null), |
| 64 | + (rr.name.indexOf("store") === 1 ? "Type.VAR_STORE" : null), |
| 65 | + (rr.name.indexOf("aload") === 1 ? "Type.ARRAY_LOAD" : null), |
| 66 | + (rr.name.indexOf("astore") === 1 ? "Type.ARRAY_STORE" : null), |
| 67 | + (rr.name.indexOf("return") > -1 ? "Type.RETURN" : null), |
| 68 | + (isCondition ? "Type.CONDITION" : null), |
| 69 | + (isJump ? "Type.JUMP" : null), |
| 70 | + (isCpIndex ? "Type.CP_INDEX" : null) |
| 71 | + ].filter(s => s != null)).length > 0 ? "enums(" + types.join(", ") + ")" : "none(Type.class)") + |
| 72 | + ", " + |
| 73 | + ((opUtils = [ |
| 74 | + (isCondition || isJump ? "IoUtility.offsetModifier(1, " + (rr.name.endsWith("_w") ? 4 : 2) + ")" : null), |
| 75 | + (isCpIndex ? "IoUtility.cpIndex(1, " + (rr.name.endsWith("_w") ? 4 : 2) + ")" : null), |
| 76 | + (rr.name === "tableswitch" ? "IoUtility.TableswitchOffsetModifier" : null), |
| 77 | + (rr.name === "lookupswitch" ? "IoUtility.LookupswitchOffsetModifier" : null) |
| 78 | + ].filter(s => s != null)).length > 0 ? "Op.of(" + opUtils.join(", ") + ")" : "null") + |
| 79 | + ")" + (idx < ary.length - 1 ? "," : ";") + |
| 80 | + " // " + rr.operation + "," + (!isStackManipulate ? " stack: " + JSON.stringify(rr.operandStack, undefined, " ").split("\n").map(s => s.trim()).join(" ") + "," : "") + (rr.hashLink != null ? " link: " + baseUrl + "#" + rr.hashLink : ""); |
| 81 | +}).join("\n") |
0 commit comments