Expand C++ macros in tools/generate-runtime-tests.py to increase coverage
authorjkummerow@chromium.org <jkummerow@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 16 May 2014 13:16:08 +0000 (13:16 +0000)
committerjkummerow@chromium.org <jkummerow@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 16 May 2014 13:16:08 +0000 (13:16 +0000)
R=dslomov@chromium.org

Review URL: https://codereview.chromium.org/290513002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21340 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

27 files changed:
src/runtime.cc
test/mjsunit/runtime-gen/arraybufferviewgetbytelength.js [new file with mode: 0644]
test/mjsunit/runtime-gen/arraybufferviewgetbyteoffset.js [new file with mode: 0644]
test/mjsunit/runtime-gen/dataviewgetbuffer.js [new file with mode: 0644]
test/mjsunit/runtime-gen/dataviewgetfloat32.js [new file with mode: 0644]
test/mjsunit/runtime-gen/dataviewgetfloat64.js [new file with mode: 0644]
test/mjsunit/runtime-gen/dataviewgetint16.js [new file with mode: 0644]
test/mjsunit/runtime-gen/dataviewgetint32.js [new file with mode: 0644]
test/mjsunit/runtime-gen/dataviewgetint8.js [new file with mode: 0644]
test/mjsunit/runtime-gen/dataviewgetuint16.js [new file with mode: 0644]
test/mjsunit/runtime-gen/dataviewgetuint32.js [new file with mode: 0644]
test/mjsunit/runtime-gen/dataviewgetuint8.js [new file with mode: 0644]
test/mjsunit/runtime-gen/dataviewinitialize.js
test/mjsunit/runtime-gen/dataviewsetfloat32.js [new file with mode: 0644]
test/mjsunit/runtime-gen/dataviewsetfloat64.js [new file with mode: 0644]
test/mjsunit/runtime-gen/dataviewsetint16.js [new file with mode: 0644]
test/mjsunit/runtime-gen/dataviewsetint32.js [new file with mode: 0644]
test/mjsunit/runtime-gen/dataviewsetint8.js [new file with mode: 0644]
test/mjsunit/runtime-gen/dataviewsetuint16.js [new file with mode: 0644]
test/mjsunit/runtime-gen/dataviewsetuint32.js [new file with mode: 0644]
test/mjsunit/runtime-gen/dataviewsetuint8.js [new file with mode: 0644]
test/mjsunit/runtime-gen/mathacos.js [new file with mode: 0644]
test/mjsunit/runtime-gen/mathasin.js [new file with mode: 0644]
test/mjsunit/runtime-gen/mathatan.js [new file with mode: 0644]
test/mjsunit/runtime-gen/mathlogrt.js [new file with mode: 0644]
test/mjsunit/runtime-gen/typedarraygetlength.js [new file with mode: 0644]
tools/generate-runtime-tests.py

index 98fe997..8148cc8 100644 (file)
@@ -1404,11 +1404,11 @@ static bool DataViewSetValue(
 
 
 #define DATA_VIEW_GETTER(TypeName, Type, Converter)                           \
-  RUNTIME_FUNCTION(Runtime_DataViewGet##TypeName) {                  \
+  RUNTIME_FUNCTION(Runtime_DataViewGet##TypeName) {                           \
     HandleScope scope(isolate);                                               \
     ASSERT(args.length() == 3);                                               \
     CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);                        \
-    CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1);                            \
+    CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1);                             \
     CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2);                         \
     Type result;                                                              \
     if (DataViewGetValue(                                                     \
@@ -1486,12 +1486,12 @@ double DataViewConvertValue<double>(double value) {
 
 
 #define DATA_VIEW_SETTER(TypeName, Type)                                      \
-  RUNTIME_FUNCTION(Runtime_DataViewSet##TypeName) {                  \
+  RUNTIME_FUNCTION(Runtime_DataViewSet##TypeName) {                           \
     HandleScope scope(isolate);                                               \
     ASSERT(args.length() == 4);                                               \
     CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);                        \
-    CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1);                            \
-    CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);                             \
+    CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1);                             \
+    CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);                              \
     CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3);                         \
     Type v = DataViewConvertValue<Type>(value->Number());                     \
     if (DataViewSetValue(                                                     \
diff --git a/test/mjsunit/runtime-gen/arraybufferviewgetbytelength.js b/test/mjsunit/runtime-gen/arraybufferviewgetbytelength.js
new file mode 100644 (file)
index 0000000..d150ce9
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new Int32Array(2);
+%_ArrayBufferViewGetByteLength(_holder);
diff --git a/test/mjsunit/runtime-gen/arraybufferviewgetbyteoffset.js b/test/mjsunit/runtime-gen/arraybufferviewgetbyteoffset.js
new file mode 100644 (file)
index 0000000..502795a
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new Int32Array(2);
+%_ArrayBufferViewGetByteOffset(_holder);
diff --git a/test/mjsunit/runtime-gen/dataviewgetbuffer.js b/test/mjsunit/runtime-gen/dataviewgetbuffer.js
new file mode 100644 (file)
index 0000000..b4dc225
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new DataView(new ArrayBuffer(24));
+%DataViewGetBuffer(_holder);
diff --git a/test/mjsunit/runtime-gen/dataviewgetfloat32.js b/test/mjsunit/runtime-gen/dataviewgetfloat32.js
new file mode 100644 (file)
index 0000000..3d377a2
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new DataView(new ArrayBuffer(24));
+var _offset = 1.5;
+var _is_little_endian = true;
+%DataViewGetFloat32(_holder, _offset, _is_little_endian);
diff --git a/test/mjsunit/runtime-gen/dataviewgetfloat64.js b/test/mjsunit/runtime-gen/dataviewgetfloat64.js
new file mode 100644 (file)
index 0000000..82fc220
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new DataView(new ArrayBuffer(24));
+var _offset = 1.5;
+var _is_little_endian = true;
+%DataViewGetFloat64(_holder, _offset, _is_little_endian);
diff --git a/test/mjsunit/runtime-gen/dataviewgetint16.js b/test/mjsunit/runtime-gen/dataviewgetint16.js
new file mode 100644 (file)
index 0000000..e418ed2
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new DataView(new ArrayBuffer(24));
+var _offset = 1.5;
+var _is_little_endian = true;
+%DataViewGetInt16(_holder, _offset, _is_little_endian);
diff --git a/test/mjsunit/runtime-gen/dataviewgetint32.js b/test/mjsunit/runtime-gen/dataviewgetint32.js
new file mode 100644 (file)
index 0000000..787101d
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new DataView(new ArrayBuffer(24));
+var _offset = 1.5;
+var _is_little_endian = true;
+%DataViewGetInt32(_holder, _offset, _is_little_endian);
diff --git a/test/mjsunit/runtime-gen/dataviewgetint8.js b/test/mjsunit/runtime-gen/dataviewgetint8.js
new file mode 100644 (file)
index 0000000..d3a3864
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new DataView(new ArrayBuffer(24));
+var _offset = 1.5;
+var _is_little_endian = true;
+%DataViewGetInt8(_holder, _offset, _is_little_endian);
diff --git a/test/mjsunit/runtime-gen/dataviewgetuint16.js b/test/mjsunit/runtime-gen/dataviewgetuint16.js
new file mode 100644 (file)
index 0000000..0437811
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new DataView(new ArrayBuffer(24));
+var _offset = 1.5;
+var _is_little_endian = true;
+%DataViewGetUint16(_holder, _offset, _is_little_endian);
diff --git a/test/mjsunit/runtime-gen/dataviewgetuint32.js b/test/mjsunit/runtime-gen/dataviewgetuint32.js
new file mode 100644 (file)
index 0000000..af5122d
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new DataView(new ArrayBuffer(24));
+var _offset = 1.5;
+var _is_little_endian = true;
+%DataViewGetUint32(_holder, _offset, _is_little_endian);
diff --git a/test/mjsunit/runtime-gen/dataviewgetuint8.js b/test/mjsunit/runtime-gen/dataviewgetuint8.js
new file mode 100644 (file)
index 0000000..77e2c2d
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new DataView(new ArrayBuffer(24));
+var _offset = 1.5;
+var _is_little_endian = true;
+%DataViewGetUint8(_holder, _offset, _is_little_endian);
index 901a1a5..7702f4e 100644 (file)
@@ -1,7 +1,7 @@
 // Copyright 2014 the V8 project authors. All rights reserved.
 // AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
 // Flags: --allow-natives-syntax --harmony
-var _holder = new DataView(new ArrayBuffer(8));
+var _holder = new DataView(new ArrayBuffer(24));
 var _buffer = new ArrayBuffer(8);
 var _byte_offset = 1.5;
 var _byte_length = 1.5;
diff --git a/test/mjsunit/runtime-gen/dataviewsetfloat32.js b/test/mjsunit/runtime-gen/dataviewsetfloat32.js
new file mode 100644 (file)
index 0000000..009bbcc
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new DataView(new ArrayBuffer(24));
+var _offset = 1.5;
+var _value = 1.5;
+var _is_little_endian = true;
+%DataViewSetFloat32(_holder, _offset, _value, _is_little_endian);
diff --git a/test/mjsunit/runtime-gen/dataviewsetfloat64.js b/test/mjsunit/runtime-gen/dataviewsetfloat64.js
new file mode 100644 (file)
index 0000000..97c5d3e
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new DataView(new ArrayBuffer(24));
+var _offset = 1.5;
+var _value = 1.5;
+var _is_little_endian = true;
+%DataViewSetFloat64(_holder, _offset, _value, _is_little_endian);
diff --git a/test/mjsunit/runtime-gen/dataviewsetint16.js b/test/mjsunit/runtime-gen/dataviewsetint16.js
new file mode 100644 (file)
index 0000000..27b608b
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new DataView(new ArrayBuffer(24));
+var _offset = 1.5;
+var _value = 1.5;
+var _is_little_endian = true;
+%DataViewSetInt16(_holder, _offset, _value, _is_little_endian);
diff --git a/test/mjsunit/runtime-gen/dataviewsetint32.js b/test/mjsunit/runtime-gen/dataviewsetint32.js
new file mode 100644 (file)
index 0000000..2a4164c
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new DataView(new ArrayBuffer(24));
+var _offset = 1.5;
+var _value = 1.5;
+var _is_little_endian = true;
+%DataViewSetInt32(_holder, _offset, _value, _is_little_endian);
diff --git a/test/mjsunit/runtime-gen/dataviewsetint8.js b/test/mjsunit/runtime-gen/dataviewsetint8.js
new file mode 100644 (file)
index 0000000..9990c4b
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new DataView(new ArrayBuffer(24));
+var _offset = 1.5;
+var _value = 1.5;
+var _is_little_endian = true;
+%DataViewSetInt8(_holder, _offset, _value, _is_little_endian);
diff --git a/test/mjsunit/runtime-gen/dataviewsetuint16.js b/test/mjsunit/runtime-gen/dataviewsetuint16.js
new file mode 100644 (file)
index 0000000..fc2800c
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new DataView(new ArrayBuffer(24));
+var _offset = 1.5;
+var _value = 1.5;
+var _is_little_endian = true;
+%DataViewSetUint16(_holder, _offset, _value, _is_little_endian);
diff --git a/test/mjsunit/runtime-gen/dataviewsetuint32.js b/test/mjsunit/runtime-gen/dataviewsetuint32.js
new file mode 100644 (file)
index 0000000..837623f
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new DataView(new ArrayBuffer(24));
+var _offset = 1.5;
+var _value = 1.5;
+var _is_little_endian = true;
+%DataViewSetUint32(_holder, _offset, _value, _is_little_endian);
diff --git a/test/mjsunit/runtime-gen/dataviewsetuint8.js b/test/mjsunit/runtime-gen/dataviewsetuint8.js
new file mode 100644 (file)
index 0000000..d1e7bc1
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new DataView(new ArrayBuffer(24));
+var _offset = 1.5;
+var _value = 1.5;
+var _is_little_endian = true;
+%DataViewSetUint8(_holder, _offset, _value, _is_little_endian);
diff --git a/test/mjsunit/runtime-gen/mathacos.js b/test/mjsunit/runtime-gen/mathacos.js
new file mode 100644 (file)
index 0000000..e09b216
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _x = 1.5;
+%MathAcos(_x);
diff --git a/test/mjsunit/runtime-gen/mathasin.js b/test/mjsunit/runtime-gen/mathasin.js
new file mode 100644 (file)
index 0000000..6f268a6
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _x = 1.5;
+%MathAsin(_x);
diff --git a/test/mjsunit/runtime-gen/mathatan.js b/test/mjsunit/runtime-gen/mathatan.js
new file mode 100644 (file)
index 0000000..2de6785
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _x = 1.5;
+%MathAtan(_x);
diff --git a/test/mjsunit/runtime-gen/mathlogrt.js b/test/mjsunit/runtime-gen/mathlogrt.js
new file mode 100644 (file)
index 0000000..fd69bc5
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _x = 1.5;
+%_MathLogRT(_x);
diff --git a/test/mjsunit/runtime-gen/typedarraygetlength.js b/test/mjsunit/runtime-gen/typedarraygetlength.js
new file mode 100644 (file)
index 0000000..422b24f
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _holder = new Int32Array(2);
+%_TypedArrayGetLength(_holder);
index 5ce4c9e..8770aa2 100755 (executable)
@@ -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.