This commit:

a) adds a Python summary provider for NSDate
 b) changes the initialization for ScriptInterpreter so that we are not passing a bulk of Python-specific function pointers around
 c) provides a new ScriptInterpreterObject class that allows for ref-count safe wrapping of scripting objects on the C++ side
 d) contains much needed performance improvements:
    1) the pointer to the Python function generating a scripted summary is now cached instead of looked up every time
    2) redundant memory reads in the Python ObjC runtime wrapper are eliminated
    3) summaries now use the m_summary_str in ValueObject to store their data instead of passing around ( == copying) an std::string object
 e) contains other minor fixes, such as adding descriptive error messages for some cases of summary generation failure

llvm-svn: 151703
This commit is contained in:
Enrico Granata
2012-02-29 03:28:49 +00:00
parent 3203f6b9da
commit 7bc0ec3aad
30 changed files with 871 additions and 456 deletions

View File

@@ -54,6 +54,62 @@ static ScriptInterpreter::SWIGPythonUpdateSynthProviderInstance g_swig_update_pr
static ScriptInterpreter::SWIGPythonCallCommand g_swig_call_command = NULL;
static ScriptInterpreter::SWIGPythonCallModuleInit g_swig_call_module_init = NULL;
// these are the Pythonic implementations of the required callbacks
// these are scripting-language specific, which is why they belong here
// we still need to use function pointers to them instead of relying
// on linkage-time resolution because the SWIG stuff and this file
// get built at different times
extern "C" bool
LLDBSwigPythonBreakpointCallbackFunction
(
const char *python_function_name,
const char *session_dictionary_name,
const lldb::StackFrameSP& sb_frame,
const lldb::BreakpointLocationSP& sb_bp_loc
);
extern "C" bool
LLDBSwigPythonCallTypeScript
(
const char *python_function_name,
void *session_dictionary,
const lldb::ValueObjectSP& valobj_sp,
void** pyfunct_wrapper,
std::string& retval
);
extern "C" void*
LLDBSwigPythonCreateSyntheticProvider
(
const std::string python_class_name,
const char *session_dictionary_name,
const lldb::ValueObjectSP& valobj_sp
);
extern "C" uint32_t LLDBSwigPython_CalculateNumChildren (void *implementor);
extern "C" void* LLDBSwigPython_GetChildAtIndex (void *implementor, uint32_t idx);
extern "C" int LLDBSwigPython_GetIndexOfChildWithName (void *implementor, const char* child_name);
extern "C" void* LLDBSWIGPython_CastPyObjectToSBValue (void* data);
extern "C" void LLDBSwigPython_UpdateSynthProviderInstance (void* implementor);
extern "C" bool LLDBSwigPythonCallCommand
(
const char *python_function_name,
const char *session_dictionary_name,
lldb::DebuggerSP& debugger,
const char* args,
std::string& err_msg,
lldb_private::CommandReturnObject& cmd_retobj
);
extern "C" bool LLDBSwigPythonCallModuleInit
(
const std::string python_module_name,
const char *session_dictionary_name,
lldb::DebuggerSP& debugger
);
static int
_check_and_flush (FILE *stream)
{
@@ -226,7 +282,7 @@ ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interprete
// WARNING: temporary code that loads Cocoa formatters - this should be done on a per-platform basis rather than loading the whole set
// and letting the individual formatter classes exploit APIs to check whether they can/cannot do their task
run_string.Clear();
run_string.Printf ("run_one_line (%s, 'import CFString, CFArray, CFDictionary, NSData, NSMachPort, NSSet, NSNotification, NSException, CFBag, CFBinaryHeap, NSURL, NSBundle, NSNumber')", m_dictionary_name.c_str());
run_string.Printf ("run_one_line (%s, 'import CFString, CFArray, CFDictionary, NSData, NSMachPort, NSSet, NSNotification, NSException, CFBag, CFBinaryHeap, NSURL, NSBundle, NSNumber, NSDate')", m_dictionary_name.c_str());
PyRun_SimpleString (run_string.GetData());
int new_count = Debugger::TestDebuggerRefCount();
@@ -1454,44 +1510,88 @@ ScriptInterpreterPython::GenerateBreakpointCommandCallbackData (StringList &user
return true;
}
std::string
ScriptInterpreterPython::CallPythonScriptFunction (const char *python_function_name,
lldb::ValueObjectSP valobj)
static PyObject*
FindSessionDictionary(const char* dict_name)
{
static std::map<ConstString,PyObject*> g_dict_map;
ConstString dict(dict_name);
std::map<ConstString,PyObject*>::iterator iter = g_dict_map.find(dict);
if (iter != g_dict_map.end())
return iter->second;
PyObject *main_mod = PyImport_AddModule ("__main__");
if (main_mod != NULL)
{
PyObject *main_dict = PyModule_GetDict (main_mod);
if ((main_dict != NULL)
&& PyDict_Check (main_dict))
{
// Go through the main dictionary looking for the correct python script interpreter dictionary
PyObject *key, *value;
Py_ssize_t pos = 0;
while (PyDict_Next (main_dict, &pos, &key, &value))
{
// We have stolen references to the key and value objects in the dictionary; we need to increment
// them now so that Python's garbage collector doesn't collect them out from under us.
Py_INCREF (key);
Py_INCREF (value);
if (strcmp (PyString_AsString (key), dict_name) == 0)
{
g_dict_map[dict] = value;
return value;
}
}
}
}
return NULL;
}
bool
ScriptInterpreterPython::GetScriptedSummary (const char *python_function_name,
lldb::ValueObjectSP valobj,
lldb::ScriptInterpreterObjectSP& callee_wrapper_sp,
std::string& retval)
{
if (!python_function_name || !(*python_function_name))
return "<no function>";
Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
if (!valobj.get())
return "<no object>";
{
retval.assign("<no object>");
return false;
}
ExecutionContext exe_ctx (valobj->GetExecutionContextRef());
Target *target = exe_ctx.GetTargetPtr();
if (!target)
return "<no target>";
Debugger &debugger = target->GetDebugger();
ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter();
ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter;
if (!script_interpreter)
return "<no python>";
std::string ret_val;
void* old_callee = (callee_wrapper_sp ? callee_wrapper_sp->GetObject() : NULL);
void* new_callee = old_callee;
bool ret_val;
if (python_function_name
&& *python_function_name)
{
{
Locker py_lock(python_interpreter);
ret_val = g_swig_typescript_callback (python_function_name,
python_interpreter->m_dictionary_name.c_str(),
valobj);
Locker py_lock(this);
{
Timer scoped_timer ("g_swig_typescript_callback","g_swig_typescript_callback");
ret_val = g_swig_typescript_callback (python_function_name,
FindSessionDictionary(m_dictionary_name.c_str()),
valobj,
&new_callee,
retval);
}
}
}
else
return "<no function name>";
{
retval.assign("<no function name>");
return false;
}
if (new_callee && old_callee != new_callee)
callee_wrapper_sp = MakeScriptObject(new_callee);
return ret_val;
@@ -1822,6 +1922,12 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname,
}
}
lldb::ScriptInterpreterObjectSP
ScriptInterpreterPython::MakeScriptObject (void* object)
{
return lldb::ScriptInterpreterObjectSP(new ScriptInterpreterPythonObject(object));
}
ScriptInterpreterPython::SynchronicityHandler::SynchronicityHandler (lldb::DebuggerSP debugger_sp,
ScriptedCommandSynchronicity synchro) :
m_debugger_sp(debugger_sp),
@@ -1914,29 +2020,19 @@ ScriptInterpreterPython::GetDocumentationForItem(const char* item)
}
void
ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback,
SWIGPythonCreateSyntheticProvider python_swig_synthetic_script,
SWIGPythonCalculateNumChildren python_swig_calc_children,
SWIGPythonGetChildAtIndex python_swig_get_child_index,
SWIGPythonGetIndexOfChildWithName python_swig_get_index_child,
SWIGPythonCastPyObjectToSBValue python_swig_cast_to_sbvalue,
SWIGPythonUpdateSynthProviderInstance python_swig_update_provider,
SWIGPythonCallCommand python_swig_call_command,
SWIGPythonCallModuleInit python_swig_call_mod_init)
ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback python_swig_init_callback)
{
g_swig_init_callback = python_swig_init_callback;
g_swig_breakpoint_callback = python_swig_breakpoint_callback;
g_swig_typescript_callback = python_swig_typescript_callback;
g_swig_synthetic_script = python_swig_synthetic_script;
g_swig_calc_children = python_swig_calc_children;
g_swig_get_child_index = python_swig_get_child_index;
g_swig_get_index_child = python_swig_get_index_child;
g_swig_cast_to_sbvalue = python_swig_cast_to_sbvalue;
g_swig_update_provider = python_swig_update_provider;
g_swig_call_command = python_swig_call_command;
g_swig_call_module_init = python_swig_call_mod_init;
g_swig_breakpoint_callback = LLDBSwigPythonBreakpointCallbackFunction;
g_swig_typescript_callback = LLDBSwigPythonCallTypeScript;
g_swig_synthetic_script = LLDBSwigPythonCreateSyntheticProvider;
g_swig_calc_children = LLDBSwigPython_CalculateNumChildren;
g_swig_get_child_index = LLDBSwigPython_GetChildAtIndex;
g_swig_get_index_child = LLDBSwigPython_GetIndexOfChildWithName;
g_swig_cast_to_sbvalue = LLDBSWIGPython_CastPyObjectToSBValue;
g_swig_update_provider = LLDBSwigPython_UpdateSynthProviderInstance;
g_swig_call_command = LLDBSwigPythonCallCommand;
g_swig_call_module_init = LLDBSwigPythonCallModuleInit;
}
void