Repository: numba/numba

Issue:
Caching affects inspect_asm
Cached function print empty asm with inspect_asm


Discussion:

Resolving patch:
diff --git a/numba/targets/codegen.py b/numba/targets/codegen.py
--- a/numba/targets/codegen.py
+++ b/numba/targets/codegen.py
@@ -1,5 +1,6 @@
 from __future__ import print_function, division, absolute_import
 
+import warnings
 import functools
 import locale
 import weakref
@@ -65,6 +66,7 @@ class CodeLibrary(object):
 
     _finalized = False
     _object_caching_enabled = False
+    _disable_inspection = False
 
     def __init__(self, codegen, name):
         self._codegen = codegen
@@ -270,22 +272,30 @@ def get_defined_functions(self):
     def get_function(self, name):
         return self._final_module.get_function(name)
 
+    def _sentry_cache_disable_inspection(self):
+        if self._disable_inspection:
+            warnings.warn('Inspection disabled for cached code. '
+                          'Invalid result is returned.')
+
     def get_llvm_str(self):
         """
         Get the human-readable form of the LLVM module.
         """
+        self._sentry_cache_disable_inspection()
         return str(self._final_module)
 
     def get_asm_str(self):
         """
         Get the human-readable assembly.
         """
+        self._sentry_cache_disable_inspection()
         return str(self._codegen._tm.emit_assembly(self._final_module))
 
     def get_function_cfg(self, name):
         """
         Get control-flow graph of the LLVM function
         """
+        self._sentry_cache_disable_inspection()
         fn = self.get_function(name)
         dot = ll.get_function_cfg(fn)
         return _CFG(dot)
@@ -312,6 +322,7 @@ def _set_compiled_object(self, value):
         if self._compiled:
             raise ValueError("library already compiled: %s" % (self,))
         self._compiled_object = value
+        self._disable_inspection = True
 
     @classmethod
     def _dump_elf(cls, buf):


Test patch:
diff --git a/numba/tests/test_codegen.py b/numba/tests/test_codegen.py
--- a/numba/tests/test_codegen.py
+++ b/numba/tests/test_codegen.py
@@ -4,6 +4,7 @@
 
 from __future__ import print_function
 
+import warnings
 import base64
 import ctypes
 import pickle
@@ -146,6 +147,45 @@ def test_unserialize_other_process_object_code(self):
         state = library.serialize_using_object_code()
         self._check_unserialize_other_process(state)
 
+    def test_cache_disabled_inspection(self):
+        """
+        """
+        library = self.compile_module(asm_sum_outer, asm_sum_inner)
+        library.enable_object_caching()
+        state = library.serialize_using_object_code()
+
+        # exercise the valid behavior
+        with warnings.catch_warnings(record=True) as w:
+            old_llvm = library.get_llvm_str()
+            old_asm = library.get_asm_str()
+            library.get_function_cfg('sum')
+        self.assertEqual(len(w), 0)
+
+        # unserialize
+        codegen = JITCPUCodegen('other_codegen')
+        library = codegen.unserialize_library(state)
+
+        # the inspection methods would warn and give incorrect result
+        with warnings.catch_warnings(record=True) as w:
+            warnings.simplefilter("always")
+            self.assertNotEqual(old_llvm, library.get_llvm_str())
+        self.assertEqual(len(w), 1)
+        self.assertIn("Inspection disabled", str(w[0].message))
+
+        with warnings.catch_warnings(record=True) as w:
+            warnings.simplefilter("always")
+            self.assertNotEqual(library.get_asm_str(), old_asm)
+        self.assertEqual(len(w), 1)
+        self.assertIn("Inspection disabled", str(w[0].message))
+
+        with warnings.catch_warnings(record=True) as w:
+            warnings.simplefilter("always")
+            with self.assertRaises(NameError) as raises:
+                library.get_function_cfg('sum')
+        self.assertEqual(len(w), 1)
+        self.assertIn("Inspection disabled", str(w[0].message))
+        self.assertIn("sum", str(raises.exception))
+
     # Lifetime tests
 
     @unittest.expectedFailure  # MCJIT removeModule leaks and it is disabled