from __future__ import print_function
import difflib
import os
import re
import sys
architecture_independent = set(['generic'])
all_unsupported_architectures_names = set(['mips32', 'mips64', 'mips_shared'])
all_architecture_names = set(['x86', 'x64', 'arm', 'arm64'])
all_shared_architecture_names = set(['x86_shared', 'arm', 'arm64'])
reBeforeArg = "(?<=[(,\s])"
reArgType = "(?P<type>[\w\s:*&]+)"
reArgName = "(?P<name>\s\w+)"
reArgDefault = "(?P<default>(?:\s=[^,)]+)?)"
reAfterArg = "(?=[,)])"
reMatchArg = re.compile(reBeforeArg + reArgType +
reArgName + reArgDefault + reAfterArg)
def get_normalized_signatures(signature, fileAnnot=None):
signature = signature.replace('static', '')
signature = signature.replace(';', ' ')
signature = re.sub(r'\s+', ' ', signature).strip()
signature = re.sub(r'\(\s+', '(', signature).strip()
signature = reMatchArg.sub('\g<type>', signature)
signature = signature.replace('MacroAssembler::', '')
archs = ['generic']
if fileAnnot:
archs = [fileAnnot['arch']]
if 'DEFINED_ON(' in signature:
archs = re.sub(
r'.*DEFINED_ON\((?P<archs>[^()]*)\).*', '\g<archs>', signature).split(',')
archs = [a.strip() for a in archs]
signature = re.sub(r'\s+DEFINED_ON\([^()]*\)', '', signature)
elif 'PER_ARCH' in signature:
archs = all_architecture_names
signature = re.sub(r'\s+PER_ARCH', '', signature)
elif 'PER_SHARED_ARCH' in signature:
archs = all_shared_architecture_names
signature = re.sub(r'\s+PER_SHARED_ARCH', '', signature)
elif 'OOL_IN_HEADER' in signature:
assert archs == ['generic']
signature = re.sub(r'\s+OOL_IN_HEADER', '', signature)
else:
pass
inline = False
if fileAnnot:
inline = fileAnnot['inline']
if 'inline ' in signature:
signature = re.sub(r'inline\s+', '', signature)
inline = True
inlinePrefx = ''
if inline:
inlinePrefx = 'inline '
signatures = [
{'arch': a, 'sig': inlinePrefx + signature}
for a in archs
]
return signatures
file_suffixes = set([
a.replace('_', '-') for a in
all_architecture_names.union(all_shared_architecture_names)
.union(all_unsupported_architectures_names)
])
def get_file_annotation(filename):
origFilename = filename
filename = filename.split('/')[-1]
inline = False
if filename.endswith('.cpp'):
filename = filename[:-len('.cpp')]
elif filename.endswith('-inl.h'):
inline = True
filename = filename[:-len('-inl.h')]
elif filename.endswith('.h'):
inline = True
filename = filename[:-len('.h')]
else:
raise Exception('unknown file name', origFilename)
arch = 'generic'
for suffix in file_suffixes:
if filename == 'MacroAssembler-' + suffix:
arch = suffix
break
return {
'inline': inline,
'arch': arch.replace('-', '_')
}
def get_macroassembler_definitions(filename):
try:
fileAnnot = get_file_annotation(filename)
except Exception:
return []
style_section = False
lines = ''
signatures = []
with open(filename) as f:
for line in f:
if '//{{{ check_macroassembler_style' in line:
if style_section:
raise 'check_macroassembler_style section already opened.'
style_section = True
braces_depth = 0
elif '//}}} check_macroassembler_style' in line:
style_section = False
if not style_section:
continue
if line.startswith('#'):
continue
line = re.sub(r'//.*', '', line)
open_curly_brace = line.find('{')
was_braces_depth = braces_depth
braces_depth = braces_depth + line.count('{') - line.count('}')
if braces_depth < 0:
raise 'check_macroassembler_style annotations are not well scoped.'
if open_curly_brace != -1 and was_braces_depth == 0:
lines = lines + line[:open_curly_brace]
if 'MacroAssembler::' in lines:
signatures.extend(
get_normalized_signatures(lines, fileAnnot))
lines = ''
continue
if braces_depth > 0:
continue
if was_braces_depth != 0:
line = line[line.rfind('}') + 1:]
last_semi_colon = line.rfind(';')
if last_semi_colon != -1:
lines = ''
line = line[last_semi_colon + 1:]
lines = lines + line
return signatures
def get_macroassembler_declaration(filename):
style_section = False
lines = ''
signatures = []
with open(filename) as f:
for line in f:
if '//{{{ check_macroassembler_decl_style' in line:
style_section = True
elif '//}}} check_macroassembler_decl_style' in line:
style_section = False
if not style_section:
continue
if line.startswith('#'):
continue
line = re.sub(r'//.*', '', line)
if len(line.strip()) == 0 or 'public:' in line or 'private:' in line:
lines = ''
continue
lines = lines + line
if ';' not in lines:
continue
if ')' not in lines:
lines = ''
continue
signatures.extend(get_normalized_signatures(lines))
lines = ''
return signatures
def append_signatures(d, sigs):
for s in sigs:
if s['sig'] not in d:
d[s['sig']] = []
d[s['sig']].append(s['arch'])
return d
def generate_file_content(signatures):
output = []
for s in sorted(signatures.keys()):
archs = set(sorted(signatures[s]))
archs -= all_unsupported_architectures_names
if len(archs.symmetric_difference(architecture_independent)) == 0:
output.append(s + ';\n')
if s.startswith('inline'):
output.append(' is defined in MacroAssembler-inl.h\n')
else:
output.append(' is defined in MacroAssembler.cpp\n')
else:
if len(archs.symmetric_difference(all_architecture_names)) == 0:
output.append(s + ' PER_ARCH;\n')
elif len(archs.symmetric_difference(all_shared_architecture_names)) == 0:
output.append(s + ' PER_SHARED_ARCH;\n')
else:
output.append(
s + ' DEFINED_ON(' + ', '.join(sorted(archs)) + ');\n')
for a in sorted(archs):
a = a.replace('_', '-')
masm = '%s/MacroAssembler-%s' % (a, a)
if s.startswith('inline'):
output.append(' is defined in %s-inl.h\n' % masm)
else:
output.append(' is defined in %s.cpp\n' % masm)
return output
def check_style():
decls = dict()
defs = dict()
root_dir = os.path.join('js', 'src', 'jit')
for dirpath, dirnames, filenames in os.walk(root_dir):
for filename in filenames:
if 'MacroAssembler' not in filename:
continue
filepath = os.path.join(dirpath, filename).replace('\\', '/')
if filepath.endswith('MacroAssembler.h'):
decls = append_signatures(
decls, get_macroassembler_declaration(filepath))
defs = append_signatures(
defs, get_macroassembler_definitions(filepath))
if not decls or not defs:
raise Exception("Did not find any definitions or declarations")
difflines = difflib.unified_diff(generate_file_content(decls),
generate_file_content(defs),
fromfile='check_macroassembler_style.py declared syntax',
tofile='check_macroassembler_style.py found definitions')
ok = True
for diffline in difflines:
ok = False
print(diffline, end='')
return ok
def main():
ok = check_style()
if ok:
print('TEST-PASS | check_macroassembler_style.py | ok')
else:
print('TEST-UNEXPECTED-FAIL | check_macroassembler_style.py | actual output does not match expected output; diff is above')
sys.exit(0 if ok else 1)
if __name__ == '__main__':
main()