1#!/usr/bin/python -B
2
3""" Usage: make_opcode_doc.py PATH_TO_MOZILLA_CENTRAL
4
5    This script generates SpiderMonkey bytecode documentation
6    from js/src/vm/Opcodes.h.
7
8    Output is written to stdout and should be pasted into the following
9    MDN page:
10    https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
11"""
12
13from __future__ import print_function
14import re
15import sys
16
17import os
18sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
19import opcode
20
21from xml.sax.saxutils import escape
22
23SOURCE_BASE = 'http://dxr.mozilla.org/mozilla-central/source'
24
25def override(value, override_value):
26    if override_value != '':
27        return override_value
28
29    return value
30
31def format_flags(flags):
32    flags = filter(lambda x: x != 'JOF_BYTE', flags)
33    if len(flags) == 0:
34        return ''
35
36    flags = map(lambda x: x.replace('JOF_', ''), flags)
37    return ' ({flags})'.format(flags=', '.join(flags))
38
39def print_opcode(opcode):
40    names_template = '{name} [-{nuses}, +{ndefs}]{flags}'
41    opcodes = sorted([opcode] + opcode.group,
42                     key=lambda opcode: opcode.name)
43    names = map(lambda code: names_template.format(name=escape(code.name),
44                                                   nuses=override(code.nuses,
45                                                                  opcode.nuses_override),
46                                                   ndefs=override(code.ndefs,
47                                                                  opcode.ndefs_override),
48                                                   flags=format_flags(code.flags)),
49                opcodes)
50    if len(opcodes) == 1:
51        values = ['{value} (0x{value:02x})'.format(value=opcode.value)]
52    else:
53        values_template = '{name}: {value} (0x{value:02x})'
54        values = map(lambda code: values_template.format(name=escape(code.name),
55                                                         value=code.value),
56                    opcodes)
57
58    print("""<dt id="{id}">{names}</dt>
59<dd>
60<table class="standard-table">
61<tbody>
62<tr><th>Value</th><td><code>{values}</code></td></tr>
63<tr><th>Operands</th><td><code>{operands}</code></td></tr>
64<tr><th>Length</th><td><code>{length}</code></td></tr>
65<tr><th>Stack Uses</th><td><code>{stack_uses}</code></td></tr>
66<tr><th>Stack Defs</th><td><code>{stack_defs}</code></td></tr>
67</tbody>
68</table>
69
70{desc}
71</dd>
72""".format(id=opcodes[0].name,
73           names='<br>'.join(names),
74           values='<br>'.join(values),
75           operands=escape(opcode.operands) or "&nbsp;",
76           length=escape(override(opcode.length,
77                                  opcode.length_override)),
78           stack_uses=escape(opcode.stack_uses) or "&nbsp;",
79           stack_defs=escape(opcode.stack_defs) or "&nbsp;",
80           desc=opcode.desc)) # desc is already escaped
81
82id_cache = dict()
83id_count = dict()
84
85def make_element_id(category, type=''):
86    key = '{}:{}'.format(category, type)
87    if key in id_cache:
88        return id_cache[key]
89
90    if type == '':
91        id = category.replace(' ', '_')
92    else:
93        id = type.replace(' ', '_')
94
95    if id in id_count:
96        id_count[id] += 1
97        id = '{}_{}'.format(id, id_count[id])
98    else:
99        id_count[id] = 1
100
101    id_cache[key] = id
102    return id
103
104def print_doc(index):
105    print("""<div>{{{{SpiderMonkeySidebar("Internals")}}}}</div>
106
107<h2 id="Bytecode_Listing">Bytecode Listing</h2>
108
109<p>This document is automatically generated from
110<a href="{source_base}/js/src/vm/Opcodes.h">Opcodes.h</a> by
111<a href="{source_base}/js/src/vm/make_opcode_doc.py">make_opcode_doc.py</a>.</p>
112""".format(source_base=SOURCE_BASE))
113
114    for (category_name, types) in index:
115        print('<h3 id="{id}">{name}</h3>'.format(name=category_name,
116                                                 id=make_element_id(category_name)))
117        for (type_name, opcodes) in types:
118            if type_name:
119                print('<h4 id="{id}">{name}</h4>'.format(name=type_name,
120                                                         id=make_element_id(category_name, type_name)))
121            print('<dl>')
122            for opcode in sorted(opcodes,
123                                 key=lambda opcode: opcode.sort_key):
124                print_opcode(opcode)
125            print('</dl>')
126
127if __name__ == '__main__':
128    if len(sys.argv) < 2:
129        print("Usage: make_opcode_doc.py PATH_TO_MOZILLA_CENTRAL",
130              file=sys.stderr)
131        sys.exit(1)
132    dir = sys.argv[1]
133
134    try:
135        index, _ = opcode.get_opcodes(dir)
136    except Exception as e:
137        print("Error: {}".format(e.args[0]), file=sys.stderr)
138        sys.exit(1)
139
140    print_doc(index)
141