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 " ", 76 length=escape(override(opcode.length, 77 opcode.length_override)), 78 stack_uses=escape(opcode.stack_uses) or " ", 79 stack_defs=escape(opcode.stack_defs) or " ", 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