diff options
Diffstat (limited to 'js/src/vm/make_opcode_doc.py')
-rwxr-xr-x | js/src/vm/make_opcode_doc.py | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/js/src/vm/make_opcode_doc.py b/js/src/vm/make_opcode_doc.py new file mode 100755 index 0000000000..11ce81a3ed --- /dev/null +++ b/js/src/vm/make_opcode_doc.py @@ -0,0 +1,195 @@ +#!/usr/bin/env python3 -B +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + + +""" Usage: python make_opcode_doc.py + + This script generates SpiderMonkey bytecode documentation + from js/src/vm/Opcodes.h. + + Output is written to stdout and should be pasted into the following + MDN page: + https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode +""" + +import os +import sys + +# Allow this script to be run from anywhere. +this_dir = os.path.dirname(os.path.realpath(__file__)) +sys.path.insert(0, this_dir) + + +from xml.sax.saxutils import escape + +import jsopcode + +try: + import markdown +except ModuleNotFoundError as exc: + if exc.name == "markdown": + # Right, most people won't have python-markdown installed. Suggest the + # most likely path to getting this running. + print("Failed to import markdown: " + exc.msg, file=sys.stderr) + if os.path.exists(os.path.join(this_dir, "venv")): + print( + "It looks like you previously created a virtualenv here. Try this:\n" + " . venv/bin/activate", + file=sys.stderr, + ) + sys.exit(1) + print( + "Try this:\n" + " pip3 install markdown\n" + "Or, if you want to avoid installing things globally:\n" + " python3 -m venv venv && . venv/bin/activate && pip3 install markdown", + file=sys.stderr, + ) + sys.exit(1) + raise exc +except ImportError as exc: + # Oh no! Markdown failed to load. Check for a specific known issue. + if exc.msg.startswith("bad magic number in 'opcode'") and os.path.isfile( + os.path.join(this_dir, "opcode.pyc") + ): + print( + "Failed to import markdown due to bug 1506380.\n" + "This is dumb--it's an old Python cache file in your directory. Try this:\n" + " rm " + this_dir + "/opcode.pyc\n" + "The file is obsolete since November 2018.", + file=sys.stderr, + ) + sys.exit(1) + raise exc + + +SOURCE_BASE = "https://searchfox.org/mozilla-central/source" + +FORMAT_TO_IGNORE = { + "JOF_BYTE", + "JOF_UINT8", + "JOF_UINT16", + "JOF_UINT24", + "JOF_UINT32", + "JOF_INT8", + "JOF_INT32", + "JOF_TABLESWITCH", + "JOF_REGEXP", + "JOF_DOUBLE", + "JOF_LOOPHEAD", + "JOF_BIGINT", +} + + +def format_format(format): + format = [flag for flag in format if flag not in FORMAT_TO_IGNORE] + if len(format) == 0: + return "" + return "<div>Format: {format}</div>\n".format(format=", ".join(format)) + + +def maybe_escape(value, format_str, fallback=""): + if value: + return format_str.format(escape(value)) + return fallback + + +OPCODE_FORMAT = """\ +<dt id="{id}">{names}</dt> +<dd> +{operands}{stack}{desc} +{format}</dd> +""" + + +def print_opcode(opcode): + opcodes = [opcode] + opcode.group + names = ", ".join(maybe_escape(code.op, "<code>{}</code>") for code in opcodes) + operands = maybe_escape(opcode.operands, "<div>Operands: <code>({})</code></div>\n") + stack_uses = maybe_escape(opcode.stack_uses, "<code>{}</code> ") + stack_defs = maybe_escape(opcode.stack_defs, " <code>{}</code>") + if stack_uses or stack_defs: + stack = "<div>Stack: {}⇒{}</div>\n".format(stack_uses, stack_defs) + else: + stack = "" + + print( + OPCODE_FORMAT.format( + id=opcodes[0].op, + names=names, + operands=operands, + stack=stack, + desc=markdown.markdown(opcode.desc), + format=format_format(opcode.format_), + ) + ) + + +id_cache = dict() +id_count = dict() + + +def make_element_id(category, type=""): + key = "{}:{}".format(category, type) + if key in id_cache: + return id_cache[key] + + if type == "": + id = category.replace(" ", "_") + else: + id = type.replace(" ", "_") + + if id in id_count: + id_count[id] += 1 + id = "{}_{}".format(id, id_count[id]) + else: + id_count[id] = 1 + + id_cache[key] = id + return id + + +def print_doc(index): + print( + """<div>{{{{SpiderMonkeySidebar("Internals")}}}}</div> + +<h2 id="Bytecode_Listing">Bytecode Listing</h2> + +<p>This document is automatically generated from +<a href="{source_base}/js/src/vm/Opcodes.h">Opcodes.h</a> by +<a href="{source_base}/js/src/vm/make_opcode_doc.py">make_opcode_doc.py</a>.</p> +""".format( + source_base=SOURCE_BASE + ) + ) + + for (category_name, types) in index: + print( + '<h3 id="{id}">{name}</h3>'.format( + name=category_name, id=make_element_id(category_name) + ) + ) + for (type_name, opcodes) in types: + if type_name: + print( + '<h4 id="{id}">{name}</h4>'.format( + name=type_name, id=make_element_id(category_name, type_name) + ) + ) + print("<dl>") + for opcode in opcodes: + print_opcode(opcode) + print("</dl>") + + +if __name__ == "__main__": + if len(sys.argv) != 1: + print("Usage: mach python make_opcode_doc.py", file=sys.stderr) + sys.exit(1) + js_src_vm_dir = os.path.dirname(os.path.realpath(__file__)) + root_dir = os.path.abspath(os.path.join(js_src_vm_dir, "..", "..", "..")) + + index, _ = jsopcode.get_opcodes(root_dir) + print_doc(index) |