| Index: tools/generate-runtime-tests.py
|
| diff --git a/tools/generate-runtime-tests.py b/tools/generate-runtime-tests.py
|
| index 5ce4c9efddc2485dc8b60a2abd61e37834e7d45d..8770aa2916b51c76e49ec2e241fe782dac4714bf 100755
|
| --- a/tools/generate-runtime-tests.py
|
| +++ b/tools/generate-runtime-tests.py
|
| @@ -16,24 +16,38 @@ import subprocess
|
| import sys
|
| import time
|
|
|
| -# TODO(jkummerow): Support DATA_VIEW_{G,S}ETTER in runtime.cc
|
| -
|
| FILENAME = "src/runtime.cc"
|
| HEADERFILENAME = "src/runtime.h"
|
| FUNCTION = re.compile("^RUNTIME_FUNCTION\(Runtime_(\w+)")
|
| ARGSLENGTH = re.compile(".*ASSERT\(.*args\.length\(\) == (\d+)\);")
|
| FUNCTIONEND = "}\n"
|
| +MACRO = re.compile(r"^#define ([^ ]+)\(([^)]*)\) *([^\\]*)\\?\n$")
|
| +FIRST_WORD = re.compile("^\s*(.*?)[\s({\[]")
|
|
|
| WORKSPACE = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), ".."))
|
| BASEPATH = os.path.join(WORKSPACE, "test", "mjsunit", "runtime-gen")
|
| THIS_SCRIPT = os.path.relpath(sys.argv[0])
|
|
|
| +# Expand these macros, they define further runtime functions.
|
| +EXPAND_MACROS = [
|
| + "BUFFER_VIEW_GETTER",
|
| + "DATA_VIEW_GETTER",
|
| + "DATA_VIEW_SETTER",
|
| + "RUNTIME_UNARY_MATH",
|
| +]
|
| +# TODO(jkummerow): We could also whitelist the following macros, but the
|
| +# functions they define are so trivial that it's unclear how much benefit
|
| +# that would provide:
|
| +# ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
|
| +# FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
|
| +# TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
|
| +
|
| # Counts of functions in each detection state. These are used to assert
|
| # that the parser doesn't bit-rot. Change the values as needed when you add,
|
| # remove or change runtime functions, but make sure we don't lose our ability
|
| # to parse them!
|
| -EXPECTED_FUNCTION_COUNT = 338
|
| -EXPECTED_FUZZABLE_COUNT = 305
|
| +EXPECTED_FUNCTION_COUNT = 362
|
| +EXPECTED_FUZZABLE_COUNT = 329
|
| EXPECTED_CCTEST_COUNT = 6
|
| EXPECTED_UNKNOWN_COUNT = 5
|
|
|
| @@ -580,6 +594,12 @@ class Generator(object):
|
| "new %sArray(%s)" % (arraytype, ", ".join(args)),
|
| fallback="new %sArray(8)" % arraytype))
|
|
|
| + def _JSArrayBufferView(self, name, recursion_budget):
|
| + if random.random() < 0.4:
|
| + return self._JSDataView(name, recursion_budget)
|
| + else:
|
| + return self._JSTypedArray(name, recursion_budget)
|
| +
|
| def _JSWeakCollection(self, name, recursion_budget):
|
| ctor = random.choice([self._JSMap, self._JSSet])
|
| return ctor(name, recursion_budget, weak="Weak")
|
| @@ -634,7 +654,8 @@ class Generator(object):
|
| "Int32": ["32", _Int32],
|
| "JSArray": ["new Array()", _JSArray],
|
| "JSArrayBuffer": ["new ArrayBuffer(8)", _JSArrayBuffer],
|
| - "JSDataView": ["new DataView(new ArrayBuffer(8))", _JSDataView],
|
| + "JSArrayBufferView": ["new Int32Array(2)", _JSArrayBufferView],
|
| + "JSDataView": ["new DataView(new ArrayBuffer(24))", _JSDataView],
|
| "JSDate": ["new Date()", _JSDate],
|
| "JSFunction": ["function() {}", _JSFunction],
|
| "JSFunctionProxy": ["Proxy.createFunction({}, function() {})",
|
| @@ -757,6 +778,45 @@ class Function(object):
|
| return "".join(s)
|
|
|
|
|
| +class Macro(object):
|
| + def __init__(self, match):
|
| + self.name = match.group(1)
|
| + self.args = [s.strip() for s in match.group(2).split(",")]
|
| + self.lines = []
|
| + self.indentation = 0
|
| + self.AddLine(match.group(3))
|
| +
|
| + def AddLine(self, line):
|
| + if not line: return
|
| + if not self.lines:
|
| + # This is the first line, detect indentation.
|
| + self.indentation = len(line) - len(line.lstrip())
|
| + line = line.rstrip("\\\n ")
|
| + if not line: return
|
| + assert len(line[:self.indentation].strip()) == 0, \
|
| + ("expected whitespace: '%s', full line: '%s'" %
|
| + (line[:self.indentation], line))
|
| + line = line[self.indentation:]
|
| + if not line: return
|
| + self.lines.append(line + "\n")
|
| +
|
| + def Finalize(self):
|
| + for arg in self.args:
|
| + pattern = re.compile(r"(##|\b)%s(##|\b)" % arg)
|
| + for i in range(len(self.lines)):
|
| + self.lines[i] = re.sub(pattern, "%%(%s)s" % arg, self.lines[i])
|
| +
|
| + def FillIn(self, arg_values):
|
| + filler = {}
|
| + assert len(arg_values) == len(self.args)
|
| + for i in range(len(self.args)):
|
| + filler[self.args[i]] = arg_values[i]
|
| + result = []
|
| + for line in self.lines:
|
| + result.append(line % filler)
|
| + return result
|
| +
|
| +
|
| # Parses HEADERFILENAME to find out which runtime functions are "inline".
|
| def FindInlineRuntimeFunctions():
|
| inline_functions = []
|
| @@ -778,47 +838,84 @@ def FindInlineRuntimeFunctions():
|
| return inline_functions
|
|
|
|
|
| -# Detects runtime functions by parsing FILENAME.
|
| -def FindRuntimeFunctions():
|
| - inline_functions = FindInlineRuntimeFunctions()
|
| - functions = []
|
| - with open(FILENAME, "r") as f:
|
| - function = None
|
| - partial_line = ""
|
| +def ReadFileAndExpandMacros(filename):
|
| + found_macros = {}
|
| + expanded_lines = []
|
| + with open(filename, "r") as f:
|
| + found_macro = None
|
| for line in f:
|
| - # Multi-line definition support, ignoring macros.
|
| - if line.startswith("RUNTIME_FUNCTION") and not line.endswith("{\n"):
|
| - if line.endswith("\\\n"): continue
|
| - partial_line = line.rstrip()
|
| + if found_macro is not None:
|
| + found_macro.AddLine(line)
|
| + if not line.endswith("\\\n"):
|
| + found_macro.Finalize()
|
| + found_macro = None
|
| continue
|
| - if partial_line:
|
| - partial_line += " " + line.strip()
|
| - if partial_line.endswith("{"):
|
| - line = partial_line
|
| - partial_line = ""
|
| - else:
|
| - continue
|
|
|
| - match = FUNCTION.match(line)
|
| + match = MACRO.match(line)
|
| if match:
|
| - function = Function(match)
|
| - if function.name in inline_functions:
|
| - function.inline = "_"
|
| + found_macro = Macro(match)
|
| + if found_macro.name in EXPAND_MACROS:
|
| + found_macros[found_macro.name] = found_macro
|
| + else:
|
| + found_macro = None
|
| continue
|
| - if function is None: continue
|
|
|
| - match = ARGSLENGTH.match(line)
|
| + match = FIRST_WORD.match(line)
|
| if match:
|
| - function.SetArgsLength(match)
|
| - continue
|
| + first_word = match.group(1)
|
| + if first_word in found_macros:
|
| + MACRO_CALL = re.compile("%s\(([^)]*)\)" % first_word)
|
| + match = MACRO_CALL.match(line)
|
| + assert match
|
| + args = [s.strip() for s in match.group(1).split(",")]
|
| + expanded_lines += found_macros[first_word].FillIn(args)
|
| + continue
|
| +
|
| + expanded_lines.append(line)
|
| + return expanded_lines
|
| +
|
|
|
| - if function.TryParseArg(line):
|
| +# Detects runtime functions by parsing FILENAME.
|
| +def FindRuntimeFunctions():
|
| + inline_functions = FindInlineRuntimeFunctions()
|
| + functions = []
|
| + expanded_lines = ReadFileAndExpandMacros(FILENAME)
|
| + function = None
|
| + partial_line = ""
|
| + for line in expanded_lines:
|
| + # Multi-line definition support, ignoring macros.
|
| + if line.startswith("RUNTIME_FUNCTION") and not line.endswith("{\n"):
|
| + if line.endswith("\\\n"): continue
|
| + partial_line = line.rstrip()
|
| + continue
|
| + if partial_line:
|
| + partial_line += " " + line.strip()
|
| + if partial_line.endswith("{"):
|
| + line = partial_line
|
| + partial_line = ""
|
| + else:
|
| continue
|
|
|
| - if line == FUNCTIONEND:
|
| - if function is not None:
|
| - functions.append(function)
|
| - function = None
|
| + match = FUNCTION.match(line)
|
| + if match:
|
| + function = Function(match)
|
| + if function.name in inline_functions:
|
| + function.inline = "_"
|
| + continue
|
| + if function is None: continue
|
| +
|
| + match = ARGSLENGTH.match(line)
|
| + if match:
|
| + function.SetArgsLength(match)
|
| + continue
|
| +
|
| + if function.TryParseArg(line):
|
| + continue
|
| +
|
| + if line == FUNCTIONEND:
|
| + if function is not None:
|
| + functions.append(function)
|
| + function = None
|
| return functions
|
|
|
| # Classifies runtime functions.
|
|
|