diff --git a/configure b/configure
index d999cfc47d87fd..8770c915761700 100755
--- a/configure
+++ b/configure
@@ -439,6 +439,11 @@ intl_optgroup.add_option('--download-path',
 
 parser.add_option_group(intl_optgroup)
 
+parser.add_option('--debug-lib',
+    action='store_true',
+    dest='node_debug_lib',
+    help='build lib with DCHECK macros')
+
 http2_optgroup.add_option('--debug-http2',
     action='store_true',
     dest='debug_http2',
@@ -949,6 +954,8 @@ def configure_node(o):
   if options.enable_static:
     o['variables']['node_target_type'] = 'static_library'
 
+  o['variables']['node_debug_lib'] = b(options.node_debug_lib)
+
   if options.debug_http2:
     o['variables']['debug_http2'] = 1
   else:
diff --git a/lib/.eslintrc.yaml b/lib/.eslintrc.yaml
index e87596d4d5c21b..4eebdb6617c101 100644
--- a/lib/.eslintrc.yaml
+++ b/lib/.eslintrc.yaml
@@ -5,3 +5,18 @@ rules:
   no-let-in-for-declaration: error
   lowercase-name-for-primitive: error
   non-ascii-character: error
+globals:
+  CHECK: false
+  CHECK_EQ: false
+  CHECK_GE: false
+  CHECK_GT: false
+  CHECK_LE: false
+  CHECK_LT: false
+  CHECK_NE: false
+  DCHECK: false
+  DCHECK_EQ: false
+  DCHECK_GE: false
+  DCHECK_GT: false
+  DCHECK_LE: false
+  DCHECK_LT: false
+  DCHECK_NE: false
diff --git a/node.gyp b/node.gyp
index 1ab7b207e21339..349f9a0b6fb755 100644
--- a/node.gyp
+++ b/node.gyp
@@ -702,6 +702,7 @@
           'inputs': [
             '<@(library_files)',
             './config.gypi',
+            'tools/check_macros.py'
           ],
           'outputs': [
             '<(SHARED_INTERMEDIATE_DIR)/node_javascript.cc',
@@ -715,6 +716,12 @@
             }],
             [ 'node_use_perfctr=="false"', {
               'inputs': [ 'src/noperfctr_macros.py' ]
+            }],
+            [ 'node_debug_lib=="false"', {
+              'inputs': [ 'tools/nodcheck_macros.py' ]
+            }],
+            [ 'node_debug_lib=="true"', {
+              'inputs': [ 'tools/dcheck_macros.py' ]
             }]
           ],
           'action': [
diff --git a/tools/check_macros.py b/tools/check_macros.py
new file mode 100644
index 00000000000000..2baf0d7f419573
--- /dev/null
+++ b/tools/check_macros.py
@@ -0,0 +1,7 @@
+macro CHECK(x) = do { if (!(x)) (process._rawDebug("CHECK: x == true"), process.abort()) } while (0);
+macro CHECK_EQ(a, b) = CHECK((a) === (b));
+macro CHECK_GE(a, b) = CHECK((a) >= (b));
+macro CHECK_GT(a, b) = CHECK((a) > (b));
+macro CHECK_LE(a, b) = CHECK((a) <= (b));
+macro CHECK_LT(a, b) = CHECK((a) < (b));
+macro CHECK_NE(a, b) = CHECK((a) !== (b));
diff --git a/tools/dcheck_macros.py b/tools/dcheck_macros.py
new file mode 100644
index 00000000000000..acc68fadb01abe
--- /dev/null
+++ b/tools/dcheck_macros.py
@@ -0,0 +1,7 @@
+macro DCHECK(x) = do { if (!(x)) (process._rawDebug("DCHECK: x == true"), process.abort()) } while (0);
+macro DCHECK_EQ(a, b) = DCHECK((a) === (b));
+macro DCHECK_GE(a, b) = DCHECK((a) >= (b));
+macro DCHECK_GT(a, b) = DCHECK((a) > (b));
+macro DCHECK_LE(a, b) = DCHECK((a) <= (b));
+macro DCHECK_LT(a, b) = DCHECK((a) < (b));
+macro DCHECK_NE(a, b) = DCHECK((a) !== (b));
diff --git a/tools/js2c.py b/tools/js2c.py
index d2d63ad571205d..fa22b0b9722ce4 100755
--- a/tools/js2c.py
+++ b/tools/js2c.py
@@ -74,20 +74,27 @@ def ExpandConstants(lines, constants):
 
 
 def ExpandMacros(lines, macros):
+  def expander(s):
+    return ExpandMacros(s, macros)
   for name, macro in macros.items():
-    start = lines.find(name + '(', 0)
-    while start != -1:
+    name_pattern = re.compile("\\b%s\\(" % name)
+    pattern_match = name_pattern.search(lines, 0)
+    while pattern_match is not None:
       # Scan over the arguments
-      assert lines[start + len(name)] == '('
       height = 1
-      end = start + len(name) + 1
+      start = pattern_match.start()
+      end = pattern_match.end()
+      assert lines[end - 1] == '('
       last_match = end
-      arg_index = 0
-      mapping = { }
+      arg_index = [0]  # Wrap state into array, to work around Python "scoping"
+      mapping = {}
       def add_arg(str):
         # Remember to expand recursively in the arguments
-        replacement = ExpandMacros(str.strip(), macros)
-        mapping[macro.args[arg_index]] = replacement
+        if arg_index[0] >= len(macro.args):
+          return
+        replacement = expander(str.strip())
+        mapping[macro.args[arg_index[0]]] = replacement
+        arg_index[0] += 1
       while end < len(lines) and height > 0:
         # We don't count commas at higher nesting levels.
         if lines[end] == ',' and height == 1:
@@ -100,10 +107,13 @@ def add_arg(str):
         end = end + 1
       # Remember to add the last match.
       add_arg(lines[last_match:end-1])
+      if arg_index[0] < len(macro.args) -1:
+        lineno = lines.count(os.linesep, 0, start) + 1
+        raise Exception('line %s: Too few arguments for macro "%s"' % (lineno, name))
       result = macro.expand(mapping)
       # Replace the occurrence of the macro with the expansion
       lines = lines[:start] + result + lines[end:]
-      start = lines.find(name + '(', start)
+      pattern_match = name_pattern.search(lines, start + len(result))
   return lines
 
 
diff --git a/tools/nodcheck_macros.py b/tools/nodcheck_macros.py
new file mode 100644
index 00000000000000..7bd2f209f511fc
--- /dev/null
+++ b/tools/nodcheck_macros.py
@@ -0,0 +1,7 @@
+macro DCHECK(x) = void(x);
+macro DCHECK_EQ(a, b) = void(a, b);
+macro DCHECK_GE(a, b) = void(a, b);
+macro DCHECK_GT(a, b) = void(a, b);
+macro DCHECK_LE(a, b) = void(a, b);
+macro DCHECK_LT(a, b) = void(a, b);
+macro DCHECK_NE(a, b) = void(a, b);