Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(340)

Side by Side Diff: tools/generate-runtime-tests.py

Issue 290513002: Expand C++ macros in tools/generate-runtime-tests.py to increase coverage (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: formatting Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « test/mjsunit/runtime-gen/typedarraygetlength.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2014 the V8 project authors. All rights reserved. 2 # Copyright 2014 the V8 project authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 import itertools 6 import itertools
7 import multiprocessing 7 import multiprocessing
8 import optparse 8 import optparse
9 import os 9 import os
10 import random 10 import random
11 import re 11 import re
12 import shutil 12 import shutil
13 import signal 13 import signal
14 import string 14 import string
15 import subprocess 15 import subprocess
16 import sys 16 import sys
17 import time 17 import time
18 18
19 # TODO(jkummerow): Support DATA_VIEW_{G,S}ETTER in runtime.cc
20
21 FILENAME = "src/runtime.cc" 19 FILENAME = "src/runtime.cc"
22 HEADERFILENAME = "src/runtime.h" 20 HEADERFILENAME = "src/runtime.h"
23 FUNCTION = re.compile("^RUNTIME_FUNCTION\(Runtime_(\w+)") 21 FUNCTION = re.compile("^RUNTIME_FUNCTION\(Runtime_(\w+)")
24 ARGSLENGTH = re.compile(".*ASSERT\(.*args\.length\(\) == (\d+)\);") 22 ARGSLENGTH = re.compile(".*ASSERT\(.*args\.length\(\) == (\d+)\);")
25 FUNCTIONEND = "}\n" 23 FUNCTIONEND = "}\n"
24 MACRO = re.compile(r"^#define ([^ ]+)\(([^)]*)\) *([^\\]*)\\?\n$")
25 FIRST_WORD = re.compile("^\s*(.*?)[\s({\[]")
26 26
27 WORKSPACE = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "..")) 27 WORKSPACE = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), ".."))
28 BASEPATH = os.path.join(WORKSPACE, "test", "mjsunit", "runtime-gen") 28 BASEPATH = os.path.join(WORKSPACE, "test", "mjsunit", "runtime-gen")
29 THIS_SCRIPT = os.path.relpath(sys.argv[0]) 29 THIS_SCRIPT = os.path.relpath(sys.argv[0])
30 30
31 # Expand these macros, they define further runtime functions.
32 EXPAND_MACROS = [
33 "BUFFER_VIEW_GETTER",
34 "DATA_VIEW_GETTER",
35 "DATA_VIEW_SETTER",
36 "RUNTIME_UNARY_MATH",
37 ]
38 # TODO(jkummerow): We could also whitelist the following macros, but the
39 # functions they define are so trivial that it's unclear how much benefit
40 # that would provide:
41 # ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
42 # FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
43 # TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
44
31 # Counts of functions in each detection state. These are used to assert 45 # Counts of functions in each detection state. These are used to assert
32 # that the parser doesn't bit-rot. Change the values as needed when you add, 46 # that the parser doesn't bit-rot. Change the values as needed when you add,
33 # remove or change runtime functions, but make sure we don't lose our ability 47 # remove or change runtime functions, but make sure we don't lose our ability
34 # to parse them! 48 # to parse them!
35 EXPECTED_FUNCTION_COUNT = 338 49 EXPECTED_FUNCTION_COUNT = 362
36 EXPECTED_FUZZABLE_COUNT = 305 50 EXPECTED_FUZZABLE_COUNT = 329
37 EXPECTED_CCTEST_COUNT = 6 51 EXPECTED_CCTEST_COUNT = 6
38 EXPECTED_UNKNOWN_COUNT = 5 52 EXPECTED_UNKNOWN_COUNT = 5
39 53
40 54
41 # Don't call these at all. 55 # Don't call these at all.
42 BLACKLISTED = [ 56 BLACKLISTED = [
43 "Abort", # Kills the process. 57 "Abort", # Kills the process.
44 "AbortJS", # Kills the process. 58 "AbortJS", # Kills the process.
45 "CompileForOnStackReplacement", # Riddled with ASSERTs. 59 "CompileForOnStackReplacement", # Riddled with ASSERTs.
46 "IS_VAR", # Not implemented in the runtime. 60 "IS_VAR", # Not implemented in the runtime.
(...skipping 526 matching lines...) Expand 10 before | Expand all | Expand 10 after
573 result += self._Int32(offset_name) 587 result += self._Int32(offset_name)
574 if die < 0.33: 588 if die < 0.33:
575 length_name = name + "_length" 589 length_name = name + "_length"
576 args.append(length_name) 590 args.append(length_name)
577 result += self._Int32(length_name) 591 result += self._Int32(length_name)
578 return (result + 592 return (result +
579 self._Variable(name, 593 self._Variable(name,
580 "new %sArray(%s)" % (arraytype, ", ".join(args)), 594 "new %sArray(%s)" % (arraytype, ", ".join(args)),
581 fallback="new %sArray(8)" % arraytype)) 595 fallback="new %sArray(8)" % arraytype))
582 596
597 def _JSArrayBufferView(self, name, recursion_budget):
598 if random.random() < 0.4:
599 return self._JSDataView(name, recursion_budget)
600 else:
601 return self._JSTypedArray(name, recursion_budget)
602
583 def _JSWeakCollection(self, name, recursion_budget): 603 def _JSWeakCollection(self, name, recursion_budget):
584 ctor = random.choice([self._JSMap, self._JSSet]) 604 ctor = random.choice([self._JSMap, self._JSSet])
585 return ctor(name, recursion_budget, weak="Weak") 605 return ctor(name, recursion_budget, weak="Weak")
586 606
587 def _PropertyDetails(self, name, recursion_budget): 607 def _PropertyDetails(self, name, recursion_budget):
588 # TODO(jkummerow): Be more clever here? 608 # TODO(jkummerow): Be more clever here?
589 return self._Int32(name) 609 return self._Int32(name)
590 610
591 def _JSObject(self, name, recursion_budget): 611 def _JSObject(self, name, recursion_budget):
592 die = random.random() 612 die = random.random()
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
627 if random.random() < 0.2: 647 if random.random() < 0.2:
628 return self._Smi(name, recursion_budget) 648 return self._Smi(name, recursion_budget)
629 return self._HeapObject(name, recursion_budget) 649 return self._HeapObject(name, recursion_budget)
630 650
631 GENERATORS = { 651 GENERATORS = {
632 "Boolean": ["true", _Boolean], 652 "Boolean": ["true", _Boolean],
633 "HeapObject": ["new Object()", _HeapObject], 653 "HeapObject": ["new Object()", _HeapObject],
634 "Int32": ["32", _Int32], 654 "Int32": ["32", _Int32],
635 "JSArray": ["new Array()", _JSArray], 655 "JSArray": ["new Array()", _JSArray],
636 "JSArrayBuffer": ["new ArrayBuffer(8)", _JSArrayBuffer], 656 "JSArrayBuffer": ["new ArrayBuffer(8)", _JSArrayBuffer],
637 "JSDataView": ["new DataView(new ArrayBuffer(8))", _JSDataView], 657 "JSArrayBufferView": ["new Int32Array(2)", _JSArrayBufferView],
658 "JSDataView": ["new DataView(new ArrayBuffer(24))", _JSDataView],
638 "JSDate": ["new Date()", _JSDate], 659 "JSDate": ["new Date()", _JSDate],
639 "JSFunction": ["function() {}", _JSFunction], 660 "JSFunction": ["function() {}", _JSFunction],
640 "JSFunctionProxy": ["Proxy.createFunction({}, function() {})", 661 "JSFunctionProxy": ["Proxy.createFunction({}, function() {})",
641 _JSFunctionProxy], 662 _JSFunctionProxy],
642 "JSGeneratorObject": ["(function*(){ yield 1; })()", _JSGeneratorObject], 663 "JSGeneratorObject": ["(function*(){ yield 1; })()", _JSGeneratorObject],
643 "JSMap": ["new Map()", _JSMap], 664 "JSMap": ["new Map()", _JSMap],
644 "JSMapIterator": ["%MapCreateIterator(new Map(), 3)", _JSMapIterator], 665 "JSMapIterator": ["%MapCreateIterator(new Map(), 3)", _JSMapIterator],
645 "JSObject": ["new Object()", _JSObject], 666 "JSObject": ["new Object()", _JSObject],
646 "JSProxy": ["Proxy.create({})", _JSProxy], 667 "JSProxy": ["Proxy.create({})", _JSProxy],
647 "JSReceiver": ["new Object()", _JSReceiver], 668 "JSReceiver": ["new Object()", _JSReceiver],
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
750 argcount = max([self.args[i].index + 1 for i in self.args]) 771 argcount = max([self.args[i].index + 1 for i in self.args])
751 else: 772 else:
752 argcount = 0 773 argcount = 0
753 for i in range(argcount): 774 for i in range(argcount):
754 if i > 0: s.append(", ") 775 if i > 0: s.append(", ")
755 s.append(self.args[i].type if i in self.args else "<unknown>") 776 s.append(self.args[i].type if i in self.args else "<unknown>")
756 s.append(")") 777 s.append(")")
757 return "".join(s) 778 return "".join(s)
758 779
759 780
781 class Macro(object):
782 def __init__(self, match):
783 self.name = match.group(1)
784 self.args = [s.strip() for s in match.group(2).split(",")]
785 self.lines = []
786 self.indentation = 0
787 self.AddLine(match.group(3))
788
789 def AddLine(self, line):
790 if not line: return
791 if not self.lines:
792 # This is the first line, detect indentation.
793 self.indentation = len(line) - len(line.lstrip())
794 line = line.rstrip("\\\n ")
795 if not line: return
796 assert len(line[:self.indentation].strip()) == 0, \
797 ("expected whitespace: '%s', full line: '%s'" %
798 (line[:self.indentation], line))
799 line = line[self.indentation:]
800 if not line: return
801 self.lines.append(line + "\n")
802
803 def Finalize(self):
804 for arg in self.args:
805 pattern = re.compile(r"(##|\b)%s(##|\b)" % arg)
806 for i in range(len(self.lines)):
807 self.lines[i] = re.sub(pattern, "%%(%s)s" % arg, self.lines[i])
808
809 def FillIn(self, arg_values):
810 filler = {}
811 assert len(arg_values) == len(self.args)
812 for i in range(len(self.args)):
813 filler[self.args[i]] = arg_values[i]
814 result = []
815 for line in self.lines:
816 result.append(line % filler)
817 return result
818
819
760 # Parses HEADERFILENAME to find out which runtime functions are "inline". 820 # Parses HEADERFILENAME to find out which runtime functions are "inline".
761 def FindInlineRuntimeFunctions(): 821 def FindInlineRuntimeFunctions():
762 inline_functions = [] 822 inline_functions = []
763 with open(HEADERFILENAME, "r") as f: 823 with open(HEADERFILENAME, "r") as f:
764 inline_list = "#define INLINE_FUNCTION_LIST(F) \\\n" 824 inline_list = "#define INLINE_FUNCTION_LIST(F) \\\n"
765 inline_opt_list = "#define INLINE_OPTIMIZED_FUNCTION_LIST(F) \\\n" 825 inline_opt_list = "#define INLINE_OPTIMIZED_FUNCTION_LIST(F) \\\n"
766 inline_function = re.compile(r"^\s*F\((\w+), \d+, \d+\)\s*\\?") 826 inline_function = re.compile(r"^\s*F\((\w+), \d+, \d+\)\s*\\?")
767 mode = "SEARCHING" 827 mode = "SEARCHING"
768 for line in f: 828 for line in f:
769 if mode == "ACTIVE": 829 if mode == "ACTIVE":
770 match = inline_function.match(line) 830 match = inline_function.match(line)
771 if match: 831 if match:
772 inline_functions.append(match.group(1)) 832 inline_functions.append(match.group(1))
773 if not line.endswith("\\\n"): 833 if not line.endswith("\\\n"):
774 mode = "SEARCHING" 834 mode = "SEARCHING"
775 elif mode == "SEARCHING": 835 elif mode == "SEARCHING":
776 if line == inline_list or line == inline_opt_list: 836 if line == inline_list or line == inline_opt_list:
777 mode = "ACTIVE" 837 mode = "ACTIVE"
778 return inline_functions 838 return inline_functions
779 839
780 840
841 def ReadFileAndExpandMacros(filename):
842 found_macros = {}
843 expanded_lines = []
844 with open(filename, "r") as f:
845 found_macro = None
846 for line in f:
847 if found_macro is not None:
848 found_macro.AddLine(line)
849 if not line.endswith("\\\n"):
850 found_macro.Finalize()
851 found_macro = None
852 continue
853
854 match = MACRO.match(line)
855 if match:
856 found_macro = Macro(match)
857 if found_macro.name in EXPAND_MACROS:
858 found_macros[found_macro.name] = found_macro
859 else:
860 found_macro = None
861 continue
862
863 match = FIRST_WORD.match(line)
864 if match:
865 first_word = match.group(1)
866 if first_word in found_macros:
867 MACRO_CALL = re.compile("%s\(([^)]*)\)" % first_word)
868 match = MACRO_CALL.match(line)
869 assert match
870 args = [s.strip() for s in match.group(1).split(",")]
871 expanded_lines += found_macros[first_word].FillIn(args)
872 continue
873
874 expanded_lines.append(line)
875 return expanded_lines
876
877
781 # Detects runtime functions by parsing FILENAME. 878 # Detects runtime functions by parsing FILENAME.
782 def FindRuntimeFunctions(): 879 def FindRuntimeFunctions():
783 inline_functions = FindInlineRuntimeFunctions() 880 inline_functions = FindInlineRuntimeFunctions()
784 functions = [] 881 functions = []
785 with open(FILENAME, "r") as f: 882 expanded_lines = ReadFileAndExpandMacros(FILENAME)
786 function = None 883 function = None
787 partial_line = "" 884 partial_line = ""
788 for line in f: 885 for line in expanded_lines:
789 # Multi-line definition support, ignoring macros. 886 # Multi-line definition support, ignoring macros.
790 if line.startswith("RUNTIME_FUNCTION") and not line.endswith("{\n"): 887 if line.startswith("RUNTIME_FUNCTION") and not line.endswith("{\n"):
791 if line.endswith("\\\n"): continue 888 if line.endswith("\\\n"): continue
792 partial_line = line.rstrip() 889 partial_line = line.rstrip()
793 continue 890 continue
794 if partial_line: 891 if partial_line:
795 partial_line += " " + line.strip() 892 partial_line += " " + line.strip()
796 if partial_line.endswith("{"): 893 if partial_line.endswith("{"):
797 line = partial_line 894 line = partial_line
798 partial_line = "" 895 partial_line = ""
799 else: 896 else:
800 continue
801
802 match = FUNCTION.match(line)
803 if match:
804 function = Function(match)
805 if function.name in inline_functions:
806 function.inline = "_"
807 continue
808 if function is None: continue
809
810 match = ARGSLENGTH.match(line)
811 if match:
812 function.SetArgsLength(match)
813 continue 897 continue
814 898
815 if function.TryParseArg(line): 899 match = FUNCTION.match(line)
816 continue 900 if match:
901 function = Function(match)
902 if function.name in inline_functions:
903 function.inline = "_"
904 continue
905 if function is None: continue
817 906
818 if line == FUNCTIONEND: 907 match = ARGSLENGTH.match(line)
819 if function is not None: 908 if match:
820 functions.append(function) 909 function.SetArgsLength(match)
821 function = None 910 continue
911
912 if function.TryParseArg(line):
913 continue
914
915 if line == FUNCTIONEND:
916 if function is not None:
917 functions.append(function)
918 function = None
822 return functions 919 return functions
823 920
824 # Classifies runtime functions. 921 # Classifies runtime functions.
825 def ClassifyFunctions(functions): 922 def ClassifyFunctions(functions):
826 # Can be fuzzed with a JavaScript testcase. 923 # Can be fuzzed with a JavaScript testcase.
827 js_fuzzable_functions = [] 924 js_fuzzable_functions = []
828 # We have enough information to fuzz these, but they need inputs that 925 # We have enough information to fuzz these, but they need inputs that
829 # cannot be created or passed around in JavaScript. 926 # cannot be created or passed around in JavaScript.
830 cctest_fuzzable_functions = [] 927 cctest_fuzzable_functions = []
831 # This script does not have enough information about these. 928 # This script does not have enough information about these.
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
1122 for i in range(len(processes)): 1219 for i in range(len(processes)):
1123 processes[i].join() 1220 processes[i].join()
1124 except KeyboardInterrupt: 1221 except KeyboardInterrupt:
1125 stop_running.set() 1222 stop_running.set()
1126 for i in range(len(processes)): 1223 for i in range(len(processes)):
1127 processes[i].join() 1224 processes[i].join()
1128 return 0 1225 return 0
1129 1226
1130 if __name__ == "__main__": 1227 if __name__ == "__main__":
1131 sys.exit(Main()) 1228 sys.exit(Main())
OLDNEW
« no previous file with comments | « test/mjsunit/runtime-gen/typedarraygetlength.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698