tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

make_opcode_doc.py (5288B)


      1 #!/usr/bin/env python3 -B
      2 # This Source Code Form is subject to the terms of the Mozilla Public
      3 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
      4 # You can obtain one at http://mozilla.org/MPL/2.0/.
      5 
      6 
      7 """Usage: python make_opcode_doc.py
      8 
      9 This script generates SpiderMonkey bytecode documentation
     10 from js/src/vm/Opcodes.h.
     11 
     12 Output is written to stdout and should be pasted into the following
     13 MDN page:
     14 https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
     15 """
     16 
     17 import os
     18 import sys
     19 
     20 # Allow this script to be run from anywhere.
     21 this_dir = os.path.dirname(os.path.realpath(__file__))
     22 sys.path.insert(0, this_dir)
     23 
     24 
     25 from xml.sax.saxutils import escape
     26 
     27 import jsopcode
     28 
     29 try:
     30    import markdown
     31 except ModuleNotFoundError as exc:
     32    if exc.name == "markdown":
     33        # Right, most people won't have python-markdown installed. Suggest the
     34        # most likely path to getting this running.
     35        print("Failed to import markdown: " + exc.msg, file=sys.stderr)
     36        if os.path.exists(os.path.join(this_dir, "venv")):
     37            print(
     38                "It looks like you previously created a virtualenv here. Try this:\n"
     39                "    . venv/bin/activate",
     40                file=sys.stderr,
     41            )
     42            sys.exit(1)
     43        print(
     44            "Try this:\n"
     45            "    pip3 install markdown\n"
     46            "Or, if you want to avoid installing things globally:\n"
     47            "    python3 -m venv venv && . venv/bin/activate && pip3 install markdown",
     48            file=sys.stderr,
     49        )
     50        sys.exit(1)
     51    raise exc
     52 except ImportError as exc:
     53    # Oh no! Markdown failed to load. Check for a specific known issue.
     54    if exc.msg.startswith("bad magic number in 'opcode'") and os.path.isfile(
     55        os.path.join(this_dir, "opcode.pyc")
     56    ):
     57        print(
     58            "Failed to import markdown due to bug 1506380.\n"
     59            "This is dumb--it's an old Python cache file in your directory. Try this:\n"
     60            "    rm " + this_dir + "/opcode.pyc\n"
     61            "The file is obsolete since November 2018.",
     62            file=sys.stderr,
     63        )
     64        sys.exit(1)
     65    raise exc
     66 
     67 
     68 SOURCE_BASE = "https://searchfox.org/mozilla-central/source"
     69 
     70 FORMAT_TO_IGNORE = {
     71    "JOF_BYTE",
     72    "JOF_UINT8",
     73    "JOF_UINT16",
     74    "JOF_UINT24",
     75    "JOF_UINT32",
     76    "JOF_INT8",
     77    "JOF_INT32",
     78    "JOF_TABLESWITCH",
     79    "JOF_REGEXP",
     80    "JOF_DOUBLE",
     81    "JOF_LOOPHEAD",
     82    "JOF_BIGINT",
     83 }
     84 
     85 
     86 def format_format(format):
     87    format = [flag for flag in format if flag not in FORMAT_TO_IGNORE]
     88    if len(format) == 0:
     89        return ""
     90    return "<div>Format: {format}</div>\n".format(format=", ".join(format))
     91 
     92 
     93 def maybe_escape(value, format_str, fallback=""):
     94    if value:
     95        return format_str.format(escape(value))
     96    return fallback
     97 
     98 
     99 OPCODE_FORMAT = """\
    100 <dt id="{id}">{names}</dt>
    101 <dd>
    102 {operands}{stack}{desc}
    103 {format}</dd>
    104 """
    105 
    106 
    107 def print_opcode(opcode):
    108    opcodes = [opcode] + opcode.group
    109    names = ", ".join(maybe_escape(code.op, "<code>{}</code>") for code in opcodes)
    110    operands = maybe_escape(opcode.operands, "<div>Operands: <code>({})</code></div>\n")
    111    stack_uses = maybe_escape(opcode.stack_uses, "<code>{}</code> ")
    112    stack_defs = maybe_escape(opcode.stack_defs, " <code>{}</code>")
    113    if stack_uses or stack_defs:
    114        stack = f"<div>Stack: {stack_uses}&rArr;{stack_defs}</div>\n"
    115    else:
    116        stack = ""
    117 
    118    print(
    119        OPCODE_FORMAT.format(
    120            id=opcodes[0].op,
    121            names=names,
    122            operands=operands,
    123            stack=stack,
    124            desc=markdown.markdown(opcode.desc),
    125            format=format_format(opcode.format_),
    126        )
    127    )
    128 
    129 
    130 id_cache = dict()
    131 id_count = dict()
    132 
    133 
    134 def make_element_id(category, type=""):
    135    key = f"{category}:{type}"
    136    if key in id_cache:
    137        return id_cache[key]
    138 
    139    if type == "":
    140        id = category.replace(" ", "_")
    141    else:
    142        id = type.replace(" ", "_")
    143 
    144    if id in id_count:
    145        id_count[id] += 1
    146        id = f"{id}_{id_count[id]}"
    147    else:
    148        id_count[id] = 1
    149 
    150    id_cache[key] = id
    151    return id
    152 
    153 
    154 def print_doc(index):
    155    print(
    156        f"""<div>{{{{SpiderMonkeySidebar("Internals")}}}}</div>
    157 
    158 <h2 id="Bytecode_Listing">Bytecode Listing</h2>
    159 
    160 <p>This document is automatically generated from
    161 <a href="{SOURCE_BASE}/js/src/vm/Opcodes.h">Opcodes.h</a> by
    162 <a href="{SOURCE_BASE}/js/src/vm/make_opcode_doc.py">make_opcode_doc.py</a>.</p>
    163 """
    164    )
    165 
    166    for category_name, types in index:
    167        print(f'<h3 id="{make_element_id(category_name)}">{category_name}</h3>')
    168        for type_name, opcodes in types:
    169            if type_name:
    170                print(
    171                    f'<h4 id="{make_element_id(category_name, type_name)}">{type_name}</h4>'
    172                )
    173            print("<dl>")
    174            for opcode in opcodes:
    175                print_opcode(opcode)
    176            print("</dl>")
    177 
    178 
    179 if __name__ == "__main__":
    180    if len(sys.argv) != 1:
    181        print("Usage: mach python make_opcode_doc.py", file=sys.stderr)
    182        sys.exit(1)
    183    js_src_vm_dir = os.path.dirname(os.path.realpath(__file__))
    184    root_dir = os.path.abspath(os.path.join(js_src_vm_dir, "..", "..", ".."))
    185 
    186    index, _ = jsopcode.get_opcodes(root_dir)
    187    print_doc(index)