[SBValue] Add a method GetNumChildren(uint32_t max)

Summary:
Along with this, support for an optional argument to the "num_children"
method of a Python synthetic child provider has also been added. These have
been added with the following use case in mind:

Synthetic child providers currently have a method "has_children" and
"num_children". While the former is good enough to know if there are
children, it does not give any insight into how many children there are.
Though the latter serves this purpose, calculating the number for children
of a data structure could be an O(N) operation if the data structure has N
children. The new method added in this change provide a middle ground.
One can call GetNumChildren(K) to know if a child exists at an index K
which can be as large as the callers tolerance can be. If the caller wants
to know about children beyond K, it can make an other call with 2K. If the
synthetic child provider maintains state about it counting till K
previosly, then the next call is only an O(K) operation. Infact, all
calls made progressively with steps of K will be O(K) operations.

Reviewers: vharron, clayborg, granata.enrico

Subscribers: labath, lldb-commits

Differential Revision: http://reviews.llvm.org/D13778

llvm-svn: 250930
diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h
index cbcfcb6..232546a 100644
--- a/lldb/include/lldb/API/SBValue.h
+++ b/lldb/include/lldb/API/SBValue.h
@@ -330,6 +330,9 @@
     uint32_t
     GetNumChildren ();
 
+    uint32_t
+    GetNumChildren (uint32_t max);
+
     void *
     GetOpaqueType();
 
diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h
index 0f97a5c..a950522 100644
--- a/lldb/include/lldb/Core/ValueObject.h
+++ b/lldb/include/lldb/Core/ValueObject.h
@@ -595,7 +595,7 @@
     GetIndexOfChildWithName (const ConstString &name);
 
     size_t
-    GetNumChildren ();
+    GetNumChildren (uint32_t max=UINT32_MAX);
 
     const Value &
     GetValue() const;
@@ -1204,7 +1204,7 @@
 
     // Should only be called by ValueObject::GetNumChildren()
     virtual size_t
-    CalculateNumChildren() = 0;
+    CalculateNumChildren(uint32_t max=UINT32_MAX) = 0;
 
     void
     SetNumChildren (size_t num_children);
diff --git a/lldb/include/lldb/Core/ValueObjectCast.h b/lldb/include/lldb/Core/ValueObjectCast.h
index 8bbc9da..215a563 100644
--- a/lldb/include/lldb/Core/ValueObjectCast.h
+++ b/lldb/include/lldb/Core/ValueObjectCast.h
@@ -35,7 +35,7 @@
     GetByteSize() override;
     
     size_t
-    CalculateNumChildren() override;
+    CalculateNumChildren(uint32_t max) override;
     
     lldb::ValueType
     GetValueType() const override;
diff --git a/lldb/include/lldb/Core/ValueObjectChild.h b/lldb/include/lldb/Core/ValueObjectChild.h
index da89534..d22eee5 100644
--- a/lldb/include/lldb/Core/ValueObjectChild.h
+++ b/lldb/include/lldb/Core/ValueObjectChild.h
@@ -56,7 +56,7 @@
     GetValueType() const override;
 
     size_t
-    CalculateNumChildren() override;
+    CalculateNumChildren(uint32_t max) override;
 
     ConstString
     GetTypeName() override;
diff --git a/lldb/include/lldb/Core/ValueObjectConstResult.h b/lldb/include/lldb/Core/ValueObjectConstResult.h
index 4848149..2a81676 100644
--- a/lldb/include/lldb/Core/ValueObjectConstResult.h
+++ b/lldb/include/lldb/Core/ValueObjectConstResult.h
@@ -76,7 +76,7 @@
     GetValueType() const override;
 
     size_t
-    CalculateNumChildren() override;
+    CalculateNumChildren(uint32_t max) override;
 
     ConstString
     GetTypeName() override;
diff --git a/lldb/include/lldb/Core/ValueObjectDynamicValue.h b/lldb/include/lldb/Core/ValueObjectDynamicValue.h
index 925f8ef..bb4738e 100644
--- a/lldb/include/lldb/Core/ValueObjectDynamicValue.h
+++ b/lldb/include/lldb/Core/ValueObjectDynamicValue.h
@@ -41,7 +41,7 @@
     GetDisplayTypeName() override;
     
     size_t
-    CalculateNumChildren() override;
+    CalculateNumChildren(uint32_t max) override;
 
     lldb::ValueType
     GetValueType() const override;
diff --git a/lldb/include/lldb/Core/ValueObjectMemory.h b/lldb/include/lldb/Core/ValueObjectMemory.h
index 7539de1..0e12fc7 100644
--- a/lldb/include/lldb/Core/ValueObjectMemory.h
+++ b/lldb/include/lldb/Core/ValueObjectMemory.h
@@ -50,7 +50,7 @@
     GetDisplayTypeName() override;
     
     size_t
-    CalculateNumChildren() override;
+    CalculateNumChildren(uint32_t max) override;
 
     lldb::ValueType
     GetValueType() const override;
diff --git a/lldb/include/lldb/Core/ValueObjectRegister.h b/lldb/include/lldb/Core/ValueObjectRegister.h
index 4e984bb..ac76f9e 100644
--- a/lldb/include/lldb/Core/ValueObjectRegister.h
+++ b/lldb/include/lldb/Core/ValueObjectRegister.h
@@ -48,7 +48,7 @@
     GetDisplayTypeName() override;
 
     size_t
-    CalculateNumChildren() override;
+    CalculateNumChildren(uint32_t max) override;
 
     ValueObject *
     CreateChildAtIndex(size_t idx, bool synthetic_array_member, int32_t synthetic_index) override;
@@ -94,7 +94,7 @@
     GetQualifiedTypeName() override;
 
     size_t
-    CalculateNumChildren() override;
+    CalculateNumChildren(uint32_t max) override;
 
     ValueObject *
     CreateChildAtIndex(size_t idx, bool synthetic_array_member, int32_t synthetic_index) override;
@@ -148,7 +148,7 @@
     GetTypeName() override;
 
     size_t
-    CalculateNumChildren() override;
+    CalculateNumChildren(uint32_t max) override;
     
     bool
     SetValueFromCString(const char *value_str, Error& error) override;
diff --git a/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h b/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h
index 33aa59a..4cdbf6e 100644
--- a/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h
+++ b/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h
@@ -49,7 +49,7 @@
     MightHaveChildren() override;
 
     size_t
-    CalculateNumChildren() override;
+    CalculateNumChildren(uint32_t max) override;
 
     lldb::ValueType
     GetValueType() const override;
diff --git a/lldb/include/lldb/Core/ValueObjectVariable.h b/lldb/include/lldb/Core/ValueObjectVariable.h
index af13a1d..3e472db 100644
--- a/lldb/include/lldb/Core/ValueObjectVariable.h
+++ b/lldb/include/lldb/Core/ValueObjectVariable.h
@@ -43,7 +43,7 @@
     GetDisplayTypeName() override;
 
     size_t
-    CalculateNumChildren() override;
+    CalculateNumChildren(uint32_t max) override;
 
     lldb::ValueType
     GetValueType() const override;
diff --git a/lldb/include/lldb/DataFormatters/TypeSynthetic.h b/lldb/include/lldb/DataFormatters/TypeSynthetic.h
index b452e22..c2e1689 100644
--- a/lldb/include/lldb/DataFormatters/TypeSynthetic.h
+++ b/lldb/include/lldb/DataFormatters/TypeSynthetic.h
@@ -56,13 +56,20 @@
         ~SyntheticChildrenFrontEnd ()
         {
         }
-        
+
         virtual size_t
         CalculateNumChildren () = 0;
+
+        virtual size_t
+        CalculateNumChildren (uint32_t max)
+        {
+            auto count = CalculateNumChildren ();
+            return count <= max ? count : max;
+        }
         
         virtual lldb::ValueObjectSP
         GetChildAtIndex (size_t idx) = 0;
-        
+
         virtual size_t
         GetIndexOfChildWithName (const ConstString &name) = 0;
         
@@ -454,7 +461,7 @@
                     return lldb::ValueObjectSP();
                 return m_backend.GetSyntheticExpressionPathChild(filter->GetExpressionPathAtIndex(idx), true);
             }
-            
+
             bool
             Update() override { return false; }
             
@@ -589,13 +596,16 @@
             IsValid ();
             
             ~FrontEnd() override;
-            
+
             size_t
             CalculateNumChildren() override;
+
+            size_t
+            CalculateNumChildren(uint32_t max) override;
             
             lldb::ValueObjectSP
             GetChildAtIndex(size_t idx) override;
-            
+
             bool
             Update() override;
             
diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
index 8a67807..5904ca7 100644
--- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -349,7 +349,7 @@
     }
 
     virtual size_t
-    CalculateNumChildren(const StructuredData::ObjectSP &implementor)
+    CalculateNumChildren(const StructuredData::ObjectSP &implementor, uint32_t max)
     {
         return 0;
     }
diff --git a/lldb/scripts/Python/python-wrapper.swig b/lldb/scripts/Python/python-wrapper.swig
index a4d9826..a2ea16a 100644
--- a/lldb/scripts/Python/python-wrapper.swig
+++ b/lldb/scripts/Python/python-wrapper.swig
@@ -113,9 +113,18 @@
     argc
     GetNumArguments ()
     {
-        if (m_callable && PyFunction_Check(m_callable))
+        PyObject *py_func_obj = NULL;
+        if (m_callable)
         {
-            PyCodeObject* code = (PyCodeObject*)PyFunction_GET_CODE(m_callable);
+            if (PyMethod_Check(m_callable))
+                py_func_obj = PyMethod_GET_FUNCTION(m_callable);
+            else
+                py_func_obj = m_callable;
+        }
+
+        if (py_func_obj)
+        {
+            PyCodeObject* code = (PyCodeObject*)PyFunction_GET_CODE(py_func_obj);
             if (code)
             {
                 size_t args = code->co_argcount;
@@ -632,15 +641,24 @@
 SWIGEXPORT size_t
 LLDBSwigPython_CalculateNumChildren
 (
-    PyObject *implementor
+    PyObject *implementor,
+    uint32_t max
 )
 {
-    size_t ret_val = UINT32_MAX;
+    size_t ret_val = 0;
     bool int_match = false;
 
-    static char callee_name[] = "num_children";
+    PyCallable pfunc = PyCallable::FindWithMemberFunction(implementor, "num_children");
 
-    PyObject* py_return = LLDBSwigPython_CallOptionalMember(implementor,callee_name, NULL);
+    if (!pfunc)
+        return ret_val;
+
+    PyObject* py_return = NULL;
+    auto argc = pfunc.GetNumArguments();
+    if (argc.num_args == 1)
+        py_return = pfunc();
+    else if (argc.num_args == 2)
+        py_return = pfunc(max);
 
     if (!py_return)
         return ret_val;
@@ -675,6 +693,9 @@
         PyErr_Clear();
     }
 
+    if (argc.num_args == 1 && ret_val > max)
+        ret_val = max;
+
     return ret_val;
 }
 
diff --git a/lldb/scripts/interface/SBValue.i b/lldb/scripts/interface/SBValue.i
index 725c551..ff201d4 100644
--- a/lldb/scripts/interface/SBValue.i
+++ b/lldb/scripts/interface/SBValue.i
@@ -238,7 +238,7 @@
     GetChildAtIndex (uint32_t idx, 
                      lldb::DynamicValueType use_dynamic,
                      bool can_create_synthetic);
-    
+
     lldb::SBValue
     CreateChildAtOffset (const char *name, uint32_t offset, lldb::SBType type);
     
@@ -321,6 +321,21 @@
     uint32_t
     GetNumChildren ();
 
+    %feature("doctstring", "
+    //------------------------------------------------------------------
+    /// Returns the number for children. 
+    ///
+    /// @param[in] max
+    ///     If max is less the lldb.UINT32_MAX, then the returned value is
+    ///     capped to max.
+    ///
+    /// @return
+    ///     An integer value capped to the argument max.
+    //------------------------------------------------------------------
+    ") GetNumChildren;
+    uint32_t
+    GetNumChildren (uint32_t max);
+
     void *
     GetOpaqueType();
 
diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp
index d71fc40..6a55880 100644
--- a/lldb/source/API/SBValue.cpp
+++ b/lldb/source/API/SBValue.cpp
@@ -1266,22 +1266,27 @@
 uint32_t
 SBValue::GetNumChildren ()
 {
+    return GetNumChildren (UINT32_MAX);
+}
+
+uint32_t
+SBValue::GetNumChildren (uint32_t max)
+{
     uint32_t num_children = 0;
 
     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
     ValueLocker locker;
     lldb::ValueObjectSP value_sp(GetSP(locker));
     if (value_sp)
-        num_children = value_sp->GetNumChildren();
+        num_children = value_sp->GetNumChildren(max);
 
     if (log)
-        log->Printf ("SBValue(%p)::GetNumChildren () => %u",
-                     static_cast<void*>(value_sp.get()), num_children);
+        log->Printf ("SBValue(%p)::GetNumChildren (%u) => %u",
+                     static_cast<void*>(value_sp.get()), max, num_children);
 
     return num_children;
 }
 
-
 SBValue
 SBValue::Dereference ()
 {
diff --git a/lldb/source/API/SystemInitializerFull.cpp b/lldb/source/API/SystemInitializerFull.cpp
index d3df421..ddf8627 100644
--- a/lldb/source/API/SystemInitializerFull.cpp
+++ b/lldb/source/API/SystemInitializerFull.cpp
@@ -149,7 +149,7 @@
                               bool &got_error);
 
 extern "C" size_t
-LLDBSwigPython_CalculateNumChildren (void *implementor);
+LLDBSwigPython_CalculateNumChildren (void *implementor, uint32_t max);
 
 extern "C" void *
 LLDBSwigPython_GetChildAtIndex (void *implementor, uint32_t idx);
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index 708526d..ecafd20 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -770,9 +770,21 @@
 
 
 size_t
-ValueObject::GetNumChildren ()
+ValueObject::GetNumChildren (uint32_t max)
 {
     UpdateValueIfNeeded();
+
+    if (max < UINT32_MAX)
+    {
+        if (m_children_count_valid)
+        {
+            size_t children_count = m_children.GetChildrenCount();
+            return children_count <= max ? children_count : max;
+        }
+        else
+            return CalculateNumChildren(max);
+    }
+
     if (!m_children_count_valid)
     {
         SetNumChildren (CalculateNumChildren());
diff --git a/lldb/source/Core/ValueObjectCast.cpp b/lldb/source/Core/ValueObjectCast.cpp
index ac75620..1c5838b8 100644
--- a/lldb/source/Core/ValueObjectCast.cpp
+++ b/lldb/source/Core/ValueObjectCast.cpp
@@ -68,9 +68,10 @@
 }
 
 size_t
-ValueObjectCast::CalculateNumChildren()
+ValueObjectCast::CalculateNumChildren(uint32_t max)
 {
-    return GetCompilerType().GetNumChildren (true);
+    auto children_count = GetCompilerType().GetNumChildren (true);
+    return children_count <= max ? children_count : max;
 }
 
 uint64_t
diff --git a/lldb/source/Core/ValueObjectChild.cpp b/lldb/source/Core/ValueObjectChild.cpp
index 7e95da6..8b579a5 100644
--- a/lldb/source/Core/ValueObjectChild.cpp
+++ b/lldb/source/Core/ValueObjectChild.cpp
@@ -62,9 +62,10 @@
 }
 
 size_t
-ValueObjectChild::CalculateNumChildren()
+ValueObjectChild::CalculateNumChildren(uint32_t max)
 {
-    return GetCompilerType().GetNumChildren (true);
+    auto children_count = GetCompilerType().GetNumChildren (true);
+    return children_count <= max ? children_count : max;
 }
 
 static void
diff --git a/lldb/source/Core/ValueObjectConstResult.cpp b/lldb/source/Core/ValueObjectConstResult.cpp
index 6154829..a0f1737 100644
--- a/lldb/source/Core/ValueObjectConstResult.cpp
+++ b/lldb/source/Core/ValueObjectConstResult.cpp
@@ -270,9 +270,10 @@
 }
 
 size_t
-ValueObjectConstResult::CalculateNumChildren()
+ValueObjectConstResult::CalculateNumChildren(uint32_t max)
 {
-    return GetCompilerType().GetNumChildren (true);
+    auto children_count = GetCompilerType().GetNumChildren (true);
+    return children_count <= max ? children_count : max;
 }
 
 ConstString
diff --git a/lldb/source/Core/ValueObjectDynamicValue.cpp b/lldb/source/Core/ValueObjectDynamicValue.cpp
index 3de12e5..cec2ca5 100644
--- a/lldb/source/Core/ValueObjectDynamicValue.cpp
+++ b/lldb/source/Core/ValueObjectDynamicValue.cpp
@@ -113,13 +113,16 @@
 }
 
 size_t
-ValueObjectDynamicValue::CalculateNumChildren()
+ValueObjectDynamicValue::CalculateNumChildren(uint32_t max)
 {
     const bool success = UpdateValueIfNeeded(false);
     if (success && m_dynamic_type_info.HasType())
-        return GetCompilerType().GetNumChildren (true);
+    {
+        auto children_count = GetCompilerType().GetNumChildren (true);
+        return children_count <= max ? children_count : max;
+    }
     else
-        return m_parent->GetNumChildren();
+        return m_parent->GetNumChildren(max);
 }
 
 uint64_t
diff --git a/lldb/source/Core/ValueObjectMemory.cpp b/lldb/source/Core/ValueObjectMemory.cpp
index fa48351..b989710 100644
--- a/lldb/source/Core/ValueObjectMemory.cpp
+++ b/lldb/source/Core/ValueObjectMemory.cpp
@@ -156,12 +156,17 @@
 }
 
 size_t
-ValueObjectMemory::CalculateNumChildren()
+ValueObjectMemory::CalculateNumChildren(uint32_t max)
 {
     if (m_type_sp)
-        return m_type_sp->GetNumChildren(true);
+    {
+        auto child_count = m_type_sp->GetNumChildren(true);
+        return child_count <= max ? child_count : max;
+    }
+
     const bool omit_empty_base_classes = true;
-    return m_compiler_type.GetNumChildren (omit_empty_base_classes);
+    auto child_count = m_compiler_type.GetNumChildren (omit_empty_base_classes);
+    return child_count <= max ? child_count : max;
 }
 
 uint64_t
diff --git a/lldb/source/Core/ValueObjectRegister.cpp b/lldb/source/Core/ValueObjectRegister.cpp
index 1e8a415..c7845cd 100644
--- a/lldb/source/Core/ValueObjectRegister.cpp
+++ b/lldb/source/Core/ValueObjectRegister.cpp
@@ -67,9 +67,10 @@
 }
 
 size_t
-ValueObjectRegisterContext::CalculateNumChildren()
+ValueObjectRegisterContext::CalculateNumChildren(uint32_t max)
 {
-    return m_reg_ctx_sp->GetRegisterSetCount();
+    auto reg_set_count = m_reg_ctx_sp->GetRegisterSetCount();
+    return reg_set_count <= max ? reg_set_count : max;
 }
 
 uint64_t
@@ -163,11 +164,14 @@
 }
 
 size_t
-ValueObjectRegisterSet::CalculateNumChildren()
+ValueObjectRegisterSet::CalculateNumChildren(uint32_t max)
 {
     const RegisterSet *reg_set = m_reg_ctx_sp->GetRegisterSet(m_reg_set_idx);
     if (reg_set)
-        return reg_set->num_registers;
+    {
+        auto reg_count = reg_set->num_registers;
+        return reg_count <= max ? reg_count : max;
+    }
     return 0;
 }
 
@@ -338,9 +342,10 @@
 }
 
 size_t
-ValueObjectRegister::CalculateNumChildren()
+ValueObjectRegister::CalculateNumChildren(uint32_t max)
 {
-    return GetCompilerType().GetNumChildren(true);
+    auto children_count = GetCompilerType().GetNumChildren (true);
+    return children_count <= max ? children_count : max;
 }
 
 uint64_t
diff --git a/lldb/source/Core/ValueObjectSyntheticFilter.cpp b/lldb/source/Core/ValueObjectSyntheticFilter.cpp
index e82862a..0ba0282 100644
--- a/lldb/source/Core/ValueObjectSyntheticFilter.cpp
+++ b/lldb/source/Core/ValueObjectSyntheticFilter.cpp
@@ -26,7 +26,7 @@
     {}
 
     size_t
-    CalculateNumChildren()
+    CalculateNumChildren ()
     {
         return m_backend.GetNumChildren();
     }
@@ -36,7 +36,7 @@
     {
         return m_backend.GetChildAtIndex(idx, true);
     }
-    
+
     size_t
     GetIndexOfChildWithName (const ConstString &name)
     {
@@ -107,12 +107,16 @@
 }
 
 size_t
-ValueObjectSynthetic::CalculateNumChildren()
+ValueObjectSynthetic::CalculateNumChildren(uint32_t max)
 {
     UpdateValueIfNeeded();
     if (m_synthetic_children_count < UINT32_MAX)
-        return m_synthetic_children_count;
-    return (m_synthetic_children_count = m_synth_filter_ap->CalculateNumChildren());
+        return m_synthetic_children_count <= max ? m_synthetic_children_count : max;
+
+    if (max < UINT32_MAX)
+        return m_synth_filter_ap->CalculateNumChildren(max);
+    else
+        return (m_synthetic_children_count = m_synth_filter_ap->CalculateNumChildren(max));
 }
 
 lldb::ValueObjectSP
diff --git a/lldb/source/Core/ValueObjectVariable.cpp b/lldb/source/Core/ValueObjectVariable.cpp
index 7210740..389b7c5 100644
--- a/lldb/source/Core/ValueObjectVariable.cpp
+++ b/lldb/source/Core/ValueObjectVariable.cpp
@@ -91,7 +91,7 @@
 }
 
 size_t
-ValueObjectVariable::CalculateNumChildren()
+ValueObjectVariable::CalculateNumChildren(uint32_t max)
 {    
     CompilerType type(GetCompilerType());
     
@@ -99,7 +99,8 @@
         return 0;
     
     const bool omit_empty_base_classes = true;
-    return type.GetNumChildren(omit_empty_base_classes);
+    auto child_count = type.GetNumChildren(omit_empty_base_classes);
+    return child_count <= max ? child_count : max;
 }
 
 uint64_t
diff --git a/lldb/source/DataFormatters/TypeSynthetic.cpp b/lldb/source/DataFormatters/TypeSynthetic.cpp
index 4098d59..e49cd99 100644
--- a/lldb/source/DataFormatters/TypeSynthetic.cpp
+++ b/lldb/source/DataFormatters/TypeSynthetic.cpp
@@ -200,7 +200,15 @@
 {
     if (!m_wrapper_sp || m_interpreter == NULL)
         return 0;
-    return m_interpreter->CalculateNumChildren(m_wrapper_sp);
+    return m_interpreter->CalculateNumChildren(m_wrapper_sp, UINT32_MAX);
+}
+
+size_t
+ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren (uint32_t max)
+{
+    if (!m_wrapper_sp || m_interpreter == NULL)
+        return 0;
+    return m_interpreter->CalculateNumChildren(m_wrapper_sp, max);
 }
 
 bool
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 32e64f4..b623626 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -2199,7 +2199,7 @@
 }
 
 size_t
-ScriptInterpreterPython::CalculateNumChildren(const StructuredData::ObjectSP &implementor_sp)
+ScriptInterpreterPython::CalculateNumChildren(const StructuredData::ObjectSP &implementor_sp, uint32_t max)
 {
     if (!implementor_sp)
         return 0;
@@ -2217,7 +2217,7 @@
     
     {
         Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
-        ret_val = g_swig_calc_children (implementor);
+        ret_val = g_swig_calc_children (implementor, max);
     }
     
     return ret_val;
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
index 2357665..cdba582 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
@@ -73,7 +73,7 @@
                                                const char *session_dictionary_name,
                                                const lldb::ProcessSP& process_sp);
     
-    typedef size_t          (*SWIGPythonCalculateNumChildren)                   (void *implementor);
+    typedef size_t          (*SWIGPythonCalculateNumChildren)                   (void *implementor, uint32_t max);
     typedef void*           (*SWIGPythonGetChildAtIndex)                        (void *implementor, uint32_t idx);
     typedef int             (*SWIGPythonGetIndexOfChildWithName)                (void *implementor, const char* child_name);
     typedef void*           (*SWIGPythonCastPyObjectToSBValue)                  (void* data);
@@ -200,7 +200,7 @@
     StructuredData::DictionarySP GetDynamicSettings(StructuredData::ObjectSP plugin_module_sp, Target *target, const char *setting_name,
                                                     lldb_private::Error &error) override;
 
-    size_t CalculateNumChildren(const StructuredData::ObjectSP &implementor) override;
+    size_t CalculateNumChildren(const StructuredData::ObjectSP &implementor, uint32_t max) override;
 
     lldb::ValueObjectSP GetChildAtIndex(const StructuredData::ObjectSP &implementor, uint32_t idx) override;
 
diff --git a/lldb/test/functionalities/data-formatter/data-formatter-synthval/TestDataFormatterSynthVal.py b/lldb/test/functionalities/data-formatter/data-formatter-synthval/TestDataFormatterSynthVal.py
index cdff8e4..65f5733 100644
--- a/lldb/test/functionalities/data-formatter/data-formatter-synthval/TestDataFormatterSynthVal.py
+++ b/lldb/test/functionalities/data-formatter/data-formatter-synthval/TestDataFormatterSynthVal.py
@@ -66,6 +66,7 @@
         # now set up the synth
         self.runCmd("script from myIntSynthProvider import *")
         self.runCmd("type synth add -l myIntSynthProvider myInt")
+        self.runCmd("type synth add -l myArraySynthProvider myArray")
         
         if self.TraceOn():
             print "x_val = %s; y_val = %s; z_val = %s" % (x_val(),y_val(),z_val())
@@ -85,6 +86,12 @@
         hi = self.frame().FindVariable("hi")
         self.assertEqual(hi.GetSummary(), "42")
 
+        ma = self.frame().FindVariable("ma")
+        self.assertTrue(ma.IsValid())
+        self.assertEqual(ma.GetNumChildren(15), 15)
+        self.assertEqual(ma.GetNumChildren(16), 16)
+        self.assertEqual(ma.GetNumChildren(17), 16)
+
 if __name__ == '__main__':
     import atexit
     lldb.SBDebugger.Initialize()
diff --git a/lldb/test/functionalities/data-formatter/data-formatter-synthval/main.cpp b/lldb/test/functionalities/data-formatter/data-formatter-synthval/main.cpp
index a77d438..accbf0a 100644
--- a/lldb/test/functionalities/data-formatter/data-formatter-synthval/main.cpp
+++ b/lldb/test/functionalities/data-formatter/data-formatter-synthval/main.cpp
@@ -5,6 +5,11 @@
     int val() { return theValue; }
 };
 
+class myArray {
+public:
+    int array[16];
+};
+
 class hasAnInt {
     public:
         myInt theInt;
@@ -18,5 +23,7 @@
     myInt y{4};
     myInt z {x+y};
     hasAnInt hi;
+    myArray ma;
+
     return z.val(); // break here
 }
diff --git a/lldb/test/functionalities/data-formatter/data-formatter-synthval/myIntSynthProvider.py b/lldb/test/functionalities/data-formatter/data-formatter-synthval/myIntSynthProvider.py
index c716836..c8517a4 100644
--- a/lldb/test/functionalities/data-formatter/data-formatter-synthval/myIntSynthProvider.py
+++ b/lldb/test/functionalities/data-formatter/data-formatter-synthval/myIntSynthProvider.py
@@ -15,3 +15,22 @@
 	def get_value(self):
 	    return self.val
 
+
+class myArraySynthProvider(object):
+    def __init__(self, valobj, dict):
+        self.valobj = valobj
+        self.array = self.valobj.GetChildMemberWithName("array")
+
+    def num_children(self, max_count):
+        if 16 < max_count:
+            return 16
+        return max_count
+
+    def get_child_at_index(self, index):
+        return None # Keep it simple when this is not tested here.
+
+    def get_child_index(self, name):
+        return None # Keep it simple when this is not tested here.
+
+    def has_children(self):
+        return True