[Libreoffice-commits] core.git: Branch 'feature/calc-parallel' - 1151 commits - accessibility/inc accessibility/source android/source apple_remote/source avmedia/inc avmedia/Library_avmedia.mk avmedia/Library_avmediaogl.mk avmedia/Library_avmediavlc.mk avmedia/Module_avmedia.mk avmedia/source basctl/source basctl/uiconfig basegfx/source basegfx/test basic/qa basic/source bean/native binaryurp/source bin/gbuild-to-ide bin/gbuild-to-ideNS bin/lo-all-static-libs bridges/inc bridges/Library_cpp_uno.mk bridges/source canvas/source chart2/inc chart2/qa chart2/source chart2/uiconfig codemaker/source comphelper/qa comphelper/source compilerplugins/clang config_host/config_features.h.in config_host/config_global.h.in config_host/config_gpgme.h.in config_host/config_lgpl.h.in config_host.mk.in configmgr/source configure.ac connectivity/qa connectivity/source cppcanvas/Library_cppcanvas.mk cppcanvas/source cppuhelper/source cppu/qa cppu/source cpputools/source cui/inc cui/source cui/uiconfig dbaccess/inc db access/source dbaccess/uiconfig desktop/inc desktop/qa desktop/source desktop/win32 dictionaries distro-configs/LibreOfficeFlatpak.conf distro-configs/LibreOfficeiOS.conf distro-configs/LibreOfficeOssFuzz.conf download.lst drawinglayer/inc drawinglayer/source dtrans/source editeng/CppunitTest_editeng_core.mk editeng/inc editeng/Library_editeng.mk editeng/qa editeng/source embeddedobj/source embedserv/source emfio/inc emfio/source extensions/source extensions/uiconfig external/coinmp external/collada2gltf external/curl external/expat external/firebird external/gpgme external/hyphen external/icu external/lcms2 external/libabw external/libassuan external/libcdr external/libebook external/libepubgen external/libetonyek external/libexttextcat external/libfreehand external/libgltf external/libgpg-error external/libjpeg-turbo external/liblangtag external/libmspub external/libmwaw external/libodfgen external/liborcus external/libpagemaker external/libqxp external/librevenge external/libstar office external/libvisio external/libwpd external/libwpg external/libwps external/libxml2 external/libxslt external/libzmf external/Module_external.mk external/nss external/opencollada external/pdfium external/redland extras/Package_tplpresnt.mk extras/source filter/qa filter/source filter/uiconfig forms/source formula/inc formula/source formula/uiconfig fpicker/source framework/inc framework/qa framework/source .git-hooks/pre-commit helpcompiler/inc helpcompiler/source helpcontent2 hwpfilter/source i18nlangtag/source i18npool/inc i18npool/source i18npool/util i18nutil/source icon-themes/breeze icon-themes/breeze_dark icon-themes/breeze_svg icon-themes/galaxy icon-themes/sifr icon-themes/sifr_dark icon-themes/sifr_svg icon-themes/tango idlc/inc idlc/source idl/inc idl/source include/avmedia include/basegfx include/basic include/codemaker include/com include/comphelper include/cppcanvas include/cppu include/cppuhelper include/editeng include/filter include/formula include/i18nlangtag include/i18nutil include/jvmaccess include/jvmfwk include/LibreOfficeKit include/o3tl include/oox include/osl include/registry include/rtl include/sal include/salhelper include/sax include/sfx2 include/svl include/svtools include/svx include/systools include/test include/toolkit include/tools include/typelib include/ucbhelper include/uno include/unotools include/vbahelper include/vcl include/xmloff include/xmlreader io/qa ios/CustomTarget_iOS.mk ios/.gitignore ios/LibreOfficeKit ios/LibreOfficeLight ios/loApp.xcconfig.in ios/loKit.xcconfig.in io/source javaunohelper/source jurt/source jvmaccess/source jvmfwk/inc jvmfwk/plugins jvmfwk/source l10ntools/inc l10ntools/source libreofficekit/Module_libreofficekit.mk libreofficekit/qa libreofficekit/source lingucomponent/Library_hyphen.mk lingucomponent/Library_lnth.mk lingucomponent/Library_MacOSXSpell.mk lingucomponent/Library_spell.mk lingucomponent/source linguistic/source lotuswordpro/inc lotuswordpro/Library_lwpft.mk lotuswordpro/so urce Makefile.fetch Makefile.in mysqlc/source o3tl/CppunitTest_o3tl_tests.mk o3tl/qa odk/examples odk/qa odk/source offapi/com offapi/UnoApi_offapi.mk officecfg/qa officecfg/registry onlineupdate/inc oox/inc oox/qa oox/source opencl/source package/inc package/source postprocess/Rdb_services.mk pyuno/source pyuno/zipcore qadevOOo/Jar_OOoRunner.mk qadevOOo/objdsc qadevOOo/runner qadevOOo/tests readlicense_oo/license README.md registry/source registry/tools remotebridges/source reportdesign/source reportdesign/uiconfig RepositoryExternal.mk Repository.mk sal/cppunittester salhelper/qa salhelper/source sal/osl sal/qa sal/rtl sal/textenc sax/inc sax/qa sax/source scaddins/source sccomp/source sc/CppunitTest_sc_arealinksobj.mk sc/CppunitTest_sc_cellrangesobj.mk sc/CppunitTest_sc_databaserangeobj.mk sc/CppunitTest_sc_datapilottableobj.mk sc/CppunitTest_sc_filterdescriptorbaseobj.mk sc/CppunitTest_sc_namedrangeobj.mk sc/CppunitTest_sc_namedrangesobj.mk sc/CppunitTest_sc_subtotaldescriptorba seobj.mk sc/CppunitTest_sc_subtotalfieldobj.mk sc/CppunitTest_sc_tablesheetobj.mk sc/inc sc/Module_sc.mk scp2/source sc/qa sc/README sc/res scripting/source sc/sdi sc/source sc/uiconfig sc/UIConfig_scalc.mk sdext/source sd/inc sd/Library_sdfilt.mk sd/qa sd/sdi sd/source sd/uiconfig setup_native/source sfx2/classification sfx2/CppunitTest_sfx2_misc.mk sfx2/Module_sfx2.mk sfx2/qa sfx2/sdi sfx2/source sfx2/uiconfig shell/inc shell/qa shell/source slideshow/source smoketest/smoketest.cxx smoketest/smoketest_too.cxx solenv/bin solenv/clang-cl solenv/CompilerTest_compilerplugins_clang.mk solenv/flatpak-manifest.in solenv/gbuild soltools/cpp sot/source starmath/inc starmath/qa starmath/source stoc/source store/source svgio/inc svgio/source svl/qa svl/source svtools/inc svtools/qa svtools/source svx/inc svx/sdi svx/source svx/uiconfig sw/CppunitTest_sw_ooxmlexport10.mk sw/CppunitTest_sw_ooxmlexport11.mk sw/CppunitTest_sw_uiwriter.mk sw/inc sw/Module_sw.mk sw/qa sw/sdi sw/source sw/uiconfig sw/UIConfig_swriter.mk test/Library_subsequenttest.mk test/source testtools/source toolkit/inc toolkit/source tools/qa tools/source translations ucbhelper/source ucb/qa ucb/source udkapi/com uitest/writer_tests UnoControls/inc UnoControls/source unodevtools/inc unodevtools/source unoidl/source unotest/source unotools/qa unotools/source unoxml/inc unoxml/source uui/source vbahelper/source vcl/backendtest vcl/CustomTarget_kde5_moc.mk vcl/Executable_602fuzzer.mk vcl/Executable_bmpfuzzer.mk vcl/Executable_cgmfuzzer.mk vcl/Executable_dxffuzzer.mk vcl/Executable_epsfuzzer.mk vcl/Executable_giffuzzer.mk vcl/Executable_hwpfuzzer.mk vcl/Executable_jpgfuzzer.mk vcl/Executable_lwpfuzzer.mk vcl/Executable_metfuzzer.mk vcl/Executable_olefuzzer.mk vcl/Executable_pcdfuzzer.mk vcl/Executable_pctfuzzer.mk vcl/Executable_pcxfuzzer.mk vcl/Executable_pngfuzzer.mk vcl/Executable_ppmfuzzer.mk vcl/Executable_pptfuzzer.mk vcl/Executable_psdfuzzer.mk vcl/Executable_qpwfuzzer.mk vcl/Executable_rasfuzzer.mk v cl/Executable_rtffuzzer.mk vcl/Executable_slkfuzzer.mk vcl/Executable_svmfuzzer.mk vcl/Executable_tgafuzzer.mk vcl/Executable_tiffuzzer.mk vcl/Executable_wmffuzzer.mk vcl/Executable_ww2fuzzer.mk vcl/Executable_ww6fuzzer.mk vcl/Executable_ww8fuzzer.mk vcl/Executable_xbmfuzzer.mk vcl/Executable_xpmfuzzer.mk vcl/headless vcl/inc vcl/ios vcl/Library_vcl.mk vcl/Library_vclplug_kde5.mk vcl/Module_vcl.mk vcl/opengl vcl/osx vcl/qa vcl/quartz vcl/README.scheduler vcl/source vcl/uiconfig vcl/unx vcl/win vcl/workben winaccessibility/inc winaccessibility/source wizards/source writerfilter/source writerperfect/inc writerperfect/qa writerperfect/source xmlhelp/source xmloff/inc xmloff/qa xmloff/source xmlscript/source xmlsecurity/inc xmlsecurity/source xmlsecurity/uiconfig

Tor Lillqvist tml at collabora.com
Tue Oct 31 10:33:18 UTC 2017


Rebased ref, commits from common ancestor:
commit a0e25475cee4cce0dbd082d1c893bd711d7a9962
Author: Tor Lillqvist <tml at collabora.com>
Date:   Mon Oct 16 18:40:51 2017 +0300

    Add OFFSET to blacklist for threaded calculation
    
    Change-Id: Ia1aaf40aa4e8e6f41ca190272365528bf37bf130

diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index db28d42ebcf3..43f0825b3f1e 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -1341,6 +1341,7 @@ void ScTokenArray::CheckToken( const FormulaToken& r )
     static const std::set<OpCode> aThreadedCalcBlackList({
         ocIndirect,
         ocMacro,
+        ocOffset,
         ocTableOp
     });
 
commit babc1820b780689b41097a9dc0346f0c1288bf90
Author: Tor Lillqvist <tml at collabora.com>
Date:   Mon Oct 16 18:31:07 2017 +0300

    Add INDIRECT to blacklist for threaded calculation
    
    Change-Id: I9a2066c396802551c3eda2c8db32b6d1a4171dfd

diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index fe007d680b30..db28d42ebcf3 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -1339,6 +1339,7 @@ bool ScTokenArray::AddFormulaToken(
 void ScTokenArray::CheckToken( const FormulaToken& r )
 {
     static const std::set<OpCode> aThreadedCalcBlackList({
+        ocIndirect,
         ocMacro,
         ocTableOp
     });
commit 6c74f5ad2696446261a7b902c284c95fa6ad1949
Author: Tor Lillqvist <tml at collabora.com>
Date:   Mon Oct 16 18:28:24 2017 +0300

    Check whether ScTokenArray::CheckToken() has disabled threading of the group
    
    Otherwise the aThreadedCalcBlackList check in CheckToken() has no
    effect, we would still attempt the threaded code path.
    
    Change-Id: I08dc2dd174459615ab8a11dbb819e39fc5437d10

diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 002d72dbad88..61b0f5a87702 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -4345,7 +4345,7 @@ bool ScFormulaCell::InterpretFormulaGroup()
         return false;
     }
 
-    if (!bThreadingProhibited && !ScCalcConfig::isOpenCLEnabled() && officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get())
+    if (!bThreadingProhibited && !ScCalcConfig::isOpenCLEnabled() && pCode->GetVectorState() != FormulaVectorDisabledNotInSubSet && officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get())
     {
         // iterate over code in the formula ...
         // ensure all input is pre-calculated -
commit 9e7bf2c755ee3cb01572d36141d6ea7cc6dc18ab
Author: Tor Lillqvist <tml at collabora.com>
Date:   Wed Oct 4 22:55:19 2017 +0300

    Avoid unused private field warning in the NDEBUG case
    
    Change-Id: I5e37b9a8325af35a15c01409f9eaa2f92459cc28

diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 73f450dc8163..a53258a2fb70 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -6747,6 +6747,7 @@ ScMutationGuard::ScMutationGuard(ScDocument* pDocument, ScMutationGuardFlags nFl
     mpDocument(pDocument),
     mnFlags(nFlags)
 {
+    (void) mpDocument;
     for (unsigned b = 0; b < static_cast<std::size_t>(ScMutationGuardFlags::N); b++)
     {
         if (static_cast<std::size_t>(mnFlags) & (1 << b))
commit 6442b4ccb2b7845918d99eebfaf786a2665fc04c
Author: Tor Lillqvist <tml at collabora.com>
Date:   Wed Oct 4 16:55:59 2017 +0300

    Move ScDocument::GetNonThreadedContext() inline
    
    Did not have any impact on performance, though.
    
    Change-Id: I7e769b4a74e0ff9e0aabfb7e291fc4b987441954

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index c86d48b6c3cf..04544fe5a64e 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -564,7 +564,11 @@ public:
 
     SC_DLLPUBLIC void  InitDrawLayer( SfxObjectShell* pDocShell = nullptr );
 
-    SC_DLLPUBLIC ScInterpreterContext     GetNonThreadedContext() const;
+    ScInterpreterContext GetNonThreadedContext() const
+    {
+        // GetFormatTable() asserts that we are not in a threaded calculation
+        return ScInterpreterContext(*this, GetFormatTable());
+    }
 
     SC_DLLPUBLIC sfx2::LinkManager*       GetLinkManager();
     SC_DLLPUBLIC const sfx2::LinkManager* GetLinkManager() const;
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 0df71931c355..73f450dc8163 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -6769,13 +6769,6 @@ ScMutationGuard::~ScMutationGuard()
 #endif
 }
 
-ScInterpreterContext ScDocument::GetNonThreadedContext() const
-{
-    // GetFormatTable() asserts that we are not in a threaded calculation
-    ScInterpreterContext aResult(*this, GetFormatTable());
-    return aResult;
-}
-
 thread_local ScDocumentThreadSpecific ScDocument::maThreadSpecific;
 
 ScRecursionHelper& ScDocument::GetRecursionHelper()
commit 4cfe1747eb16f62fda4150efe27a7a522e726216
Author: Tor Lillqvist <tml at collabora.com>
Date:   Wed Oct 4 13:11:10 2017 +0300

    Display the threaded calculation state in Help:About
    
    Change-Id: I299e555392bb4b09325ad2c92f843b1e12ee4d31

diff --git a/cui/source/dialogs/about.cxx b/cui/source/dialogs/about.cxx
index a7d219407249..c9ba680c8609 100644
--- a/cui/source/dialogs/about.cxx
+++ b/cui/source/dialogs/about.cxx
@@ -53,6 +53,7 @@
 #include <opencl/openclwrapper.hxx>
 #endif
 #include <officecfg/Office/Common.hxx>
+#include <officecfg/Office/Calc.hxx>
 
 using namespace ::com::sun::star::uno;
 using namespace ::com::sun::star::beans;
@@ -334,19 +335,31 @@ OUString AboutDialog::GetVersionString()
         sVersion += m_aLocaleStr.replaceAll("$LOCALE", aLocaleStr);
     }
 
-#if HAVE_FEATURE_OPENCL
     OUString aCalcMode = "Calc: "; // Calc calculation mode
+
+#if HAVE_FEATURE_OPENCL
     bool bSWInterp = officecfg::Office::Common::Misc::UseSwInterpreter::get();
     bool bOpenCL = openclwrapper::GPUEnv::isOpenCLEnabled();
     if (bOpenCL)
         aCalcMode += "CL";
     else if (bSWInterp)
         aCalcMode += "group";
-    else
-        aCalcMode += "single";
-    sVersion += "; " + aCalcMode;
+#else
+    const bool bOpenCL = false;
 #endif
 
+    static const bool bThreadingProhibited = std::getenv("SC_NO_THREADED_CALCULATION");
+    bool bThreadedCalc = officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get();
+
+    if (!bThreadingProhibited && !bOpenCL && bThreadedCalc)
+    {
+        if (!aCalcMode.endsWith(" "))
+            aCalcMode += " ";
+        aCalcMode += "threaded";
+    }
+
+    sVersion += "; " + aCalcMode;
+
     return sVersion;
 }
 
commit f72a7976662e8851ccff18c05e8d207dfae0ca4b
Author: Tor Lillqvist <tml at collabora.com>
Date:   Wed Oct 4 12:40:20 2017 +0300

    Make threaded calculation the default (when OpenCL is not used)
    
    Introduce a configuration setting to turn it off. For now, can also be
    turned off with the environment variable SC_NO_THREADED_CALCULATION,
    but that is probably not something we want to keep or guarantee
    staility of. (LO looks at way too many environment variables already.)
    
    Change-Id: I469cde259eda72cc2d630814a25f707f1210b0ab

diff --git a/officecfg/registry/schema/org/openoffice/Office/Calc.xcs b/officecfg/registry/schema/org/openoffice/Office/Calc.xcs
index b1feca1825c6..72ac33b99413 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Calc.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Calc.xcs
@@ -1416,6 +1416,12 @@
         <info>
           <desc>Contains settings for how to calculate formulae.</desc>
         </info>
+	<prop oor:name="UseThreadedCalculationForFormulaGroups" oor:type="xs:boolean" oor:nillable="false">
+          <info>
+            <desc>Whether to use threaded calculation of forumula groups when applicable.</desc>
+          </info>
+          <value>true</value>
+	</prop>
 	<!-- Note: The default values below probably must correspond
 	to those assigned in setOpenCLConfigToDefault() in
 	sc/source/core/tool/calcconfig.cxx
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 2d6d49bc191a..002d72dbad88 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -54,6 +54,7 @@
 #include <svl/intitem.hxx>
 #include <o3tl/make_unique.hxx>
 #include <rtl/strbuf.hxx>
+#include <officecfg/Office/Calc.hxx>
 #include <formulagroup.hxx>
 #include <listenercontext.hxx>
 #include <types.hxx>
@@ -4326,11 +4327,10 @@ bool ScFormulaCell::InterpretFormulaGroup()
         return false;
     }
 
-    static const bool bThreadingRequested = std::getenv("CPU_THREADED_CALCULATION");
+    static const bool bThreadingProhibited = std::getenv("SC_NO_THREADED_CALCULATION");
 
     // To temporarilu use threading for sc unit tests regardless of the size of the formula group,
-    // add the condition !std::getenv("LO_TESTNAME") below (with &&), and run with
-    // CPU_THREADED_CALCULATION=yes
+    // add the condition !std::getenv("LO_TESTNAME") below (with &&)
     if (GetWeight() < ScInterpreter::GetGlobalConfig().mnOpenCLMinimumFormulaGroupSize)
     {
         mxGroup->meCalcState = sc::GroupCalcDisabled;
@@ -4345,7 +4345,7 @@ bool ScFormulaCell::InterpretFormulaGroup()
         return false;
     }
 
-    if (!ScCalcConfig::isOpenCLEnabled() && bThreadingRequested)
+    if (!bThreadingProhibited && !ScCalcConfig::isOpenCLEnabled() && officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get())
     {
         // iterate over code in the formula ...
         // ensure all input is pre-calculated -
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index d0ebe0ca2e76..fe007d680b30 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -25,6 +25,7 @@
 #include <tools/mempool.hxx>
 #include <osl/diagnose.h>
 #include <sfx2/docfile.hxx>
+#include <officecfg/Office/Calc.hxx>
 
 #include <token.hxx>
 #include <tokenarray.hxx>
@@ -1346,11 +1347,11 @@ void ScTokenArray::CheckToken( const FormulaToken& r )
         // It's already disabled.  No more checking needed.
         return;
 
-    static const bool bThreadingRequested = std::getenv("CPU_THREADED_CALCULATION");
+    static const bool bThreadingProhibited = std::getenv("SC_NO_THREADED_CALCULATION");
 
     OpCode eOp = r.GetOpCode();
 
-    if (!ScCalcConfig::isOpenCLEnabled() && bThreadingRequested)
+    if (!bThreadingProhibited && !ScCalcConfig::isOpenCLEnabled() && officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get())
     {
         if (aThreadedCalcBlackList.count(eOp))
         {
commit 9b01b676860e421d2b7438f33439e80597943d0a
Author: Tor Lillqvist <tml at collabora.com>
Date:   Wed Oct 4 10:55:13 2017 +0300

    Need more ScInterpreterContexts
    
    Change-Id: I1dd679156661bb5cb025ca6cb46d19783524d5a4

diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
index 0f513c231327..00f399fab47c 100644
--- a/sc/source/core/tool/interpr6.cxx
+++ b/sc/source/core/tool/interpr6.cxx
@@ -846,7 +846,7 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                         nFuncFmtIndex = aAction.getNumberFormat();
                     }
 
-                    nFuncFmtType = pDok->GetFormatTable()->GetType( nFuncFmtIndex );
+                    nFuncFmtType = mrContext.GetFormatTable()->GetType( nFuncFmtIndex );
                 }
                 else
                 {
commit cc12cf3a86e04e4bffecd0209db2dfb8530e0d4e
Author: Tor Lillqvist <tml at collabora.com>
Date:   Wed Oct 4 08:48:05 2017 +0300

    -Werror,-Wunused-parameter
    
    Change-Id: If10c6a58f5b6f196f3644f6c592dd6d1dc0d860c

diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 62f4baa471c3..0df71931c355 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -6794,13 +6794,13 @@ ScRecursionHelper& ScDocument::GetRecursionHelper()
     }
 }
 
-void ScDocumentThreadSpecific::SetupFromNonThreadedData(const ScDocumentThreadSpecific& rNonThreadedData)
+void ScDocumentThreadSpecific::SetupFromNonThreadedData(const ScDocumentThreadSpecific& /*rNonThreadedData*/)
 {
     // What about the recursion helper?
     // Copy the lookup cache?
 }
 
-void ScDocumentThreadSpecific::MergeBackIntoNonThreadedData(ScDocumentThreadSpecific& rNonThreadedData)
+void ScDocumentThreadSpecific::MergeBackIntoNonThreadedData(ScDocumentThreadSpecific& /*rNonThreadedData*/)
 {
     // What about recursion helper and lookup cache?
 }
commit 93030470bbf89cff4156435b849198fe5973f459
Author: Tor Lillqvist <tml at collabora.com>
Date:   Wed Oct 4 08:47:02 2017 +0300

    -Werror,-Wsign-compare
    
    Change-Id: Ide03e0ae1fe97e1a09a767908a981a1e803a3474

diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index f15107bc3fe7..62f4baa471c3 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -6747,7 +6747,7 @@ ScMutationGuard::ScMutationGuard(ScDocument* pDocument, ScMutationGuardFlags nFl
     mpDocument(pDocument),
     mnFlags(nFlags)
 {
-    for (auto b = 0; b < static_cast<std::size_t>(ScMutationGuardFlags::N); b++)
+    for (unsigned b = 0; b < static_cast<std::size_t>(ScMutationGuardFlags::N); b++)
     {
         if (static_cast<std::size_t>(mnFlags) & (1 << b))
         {
@@ -6759,7 +6759,7 @@ ScMutationGuard::ScMutationGuard(ScDocument* pDocument, ScMutationGuardFlags nFl
 ScMutationGuard::~ScMutationGuard()
 {
 #ifndef NDEBUG
-    for (auto b = 0; b < static_cast<std::size_t>(ScMutationGuardFlags::N); b++)
+    for (unsigned b = 0; b < static_cast<std::size_t>(ScMutationGuardFlags::N); b++)
     {
         if (static_cast<std::size_t>(mnFlags) & (1 << b))
         {
commit f66c6fab8791d52b97337570510bca415feaa961
Author: Tor Lillqvist <tml at collabora.com>
Date:   Wed Oct 4 00:12:31 2017 +0300

    Introduce ScInterpreterContext
    
    When calculating a formula group in multiple threads in parallel, we
    need to use separate SvNumberFormatters in the threads. Possibly later
    also other things that need to be thread-local can be handled through
    the ScInterpreterContext.
    
    Why handle some thread-local things through the
    ScDocument::maNonThreaded and ScDocument::maThreadSpecific mechanism,
    and others through this ScInterpreterContext? Good question.
    
    Change-Id: I372e5fbd9a19785f55f0faf4a4bedc5fc1ef3e03

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 67bc6c348c5e..44bee716bf18 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -106,6 +106,7 @@ class ScDocumentImport;
 class ScHint;
 enum class ScMF;
 struct ScFilterEntries;
+struct ScInterpreterContext;
 
 struct ScNeededSizeOptions
 {
@@ -447,7 +448,7 @@ public:
     const ScPatternAttr*    GetPattern( SCROW nRow ) const;
     const ScPatternAttr*    GetMostUsedPattern( SCROW nStartRow, SCROW nEndRow ) const;
 
-    sal_uInt32 GetNumberFormat( SCROW nRow ) const;
+    sal_uInt32 GetNumberFormat( const ScInterpreterContext& rContext, SCROW nRow ) const;
     sal_uInt32  GetNumberFormat( SCROW nStartRow, SCROW nEndRow ) const;
 
     void        MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, bool bDeep ) const;
@@ -582,7 +583,7 @@ public:
     void SetFormulaResults( SCROW nRow, const double* pResults, size_t nLen );
     void SetFormulaResults( SCROW nRow, const formula::FormulaConstTokenRef* pResults, size_t nLen );
 
-    void CalculateInThread( SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal);
+    void CalculateInThread( const ScInterpreterContext& rContext, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal );
     void HandleStuffAfterParallelCalculation( SCROW nRow, size_t nLen );
 
     void SetNumberFormat( SCROW nRow, sal_uInt32 nNumberFormat );
diff --git a/sc/inc/dociter.hxx b/sc/inc/dociter.hxx
index 544e64ebc9c1..904f471c3c4f 100644
--- a/sc/inc/dociter.hxx
+++ b/sc/inc/dociter.hxx
@@ -45,6 +45,7 @@ struct ScQueryParam;
 struct ScDBQueryParamInternal;
 struct ScDBQueryParamMatrix;
 class ScFormulaCell;
+struct ScInterpreterContext;
 
 class ScValueIterator            // walk through all values in an area
 {
@@ -84,7 +85,7 @@ public:
         ScDocument* pDocument, const ScRange& rRange, SubtotalFlags nSubTotalFlags = SubtotalFlags::NONE,
         bool bTextAsZero = false );
 
-    void GetCurNumFmtInfo( short& nType, sal_uLong& nIndex );
+    void GetCurNumFmtInfo( const ScInterpreterContext& rContext, short& nType, sal_uLong& nIndex );
 
     /// Does NOT reset rValue if no value found!
     bool GetFirst( double& rValue, FormulaError& rErr );
@@ -125,7 +126,7 @@ private:
     {
         typedef std::pair<sc::CellStoreType::const_iterator,size_t> PositionType;
     public:
-        DataAccessInternal(ScDBQueryParamInternal* pParam, ScDocument* pDoc);
+        DataAccessInternal(ScDBQueryParamInternal* pParam, ScDocument* pDoc, const ScInterpreterContext& rContext);
         virtual ~DataAccessInternal() override;
         virtual bool getCurrent(Value& rValue) override;
         virtual bool getFirst(Value& rValue) override;
@@ -139,6 +140,7 @@ private:
         PositionType maCurPos;
         ScDBQueryParamInternal* mpParam;
         ScDocument*         mpDoc;
+        const ScInterpreterContext& mrContext;
         const ScAttrArray*  pAttrArray;
         sal_uLong               nNumFormat;     // for CalcAsShown
         sal_uLong               nNumFmtIndex;
@@ -171,7 +173,7 @@ private:
     ::std::unique_ptr<DataAccess>         mpData;
 
 public:
-                    ScDBQueryDataIterator(ScDocument* pDocument, ScDBQueryParamBase* pParam);
+                    ScDBQueryDataIterator(ScDocument* pDocument, const ScInterpreterContext& rContext, ScDBQueryParamBase* pParam);
     /// Does NOT reset rValue if no value found!
     bool            GetFirst(Value& rValue);
     /// Does NOT reset rValue if no value found!
@@ -266,6 +268,7 @@ class ScQueryCellIterator           // walk through all non-empty cells in an ar
 
     std::unique_ptr<ScQueryParam> mpParam;
     ScDocument*     pDoc;
+    const ScInterpreterContext& mrContext;
     SCTAB           nTab;
     SCCOL           nCol;
     SCROW           nRow;
@@ -292,7 +295,7 @@ class ScQueryCellIterator           // walk through all non-empty cells in an ar
     bool BinarySearch();
 
 public:
-                    ScQueryCellIterator(ScDocument* pDocument, SCTAB nTable,
+                    ScQueryCellIterator(ScDocument* pDocument, const ScInterpreterContext& rContext, SCTAB nTable,
                                         const ScQueryParam& aParam, bool bMod);
                                         // when !bMod, the QueryParam has to be filled
                                         // (bIsString)
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index e85b4ba29365..c86d48b6c3cf 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -26,6 +26,7 @@
 #include <com/sun/star/uno/Reference.hxx>
 #include <vcl/vclptr.hxx>
 #include "scdllapi.h"
+#include "interpretercontext.hxx"
 #include "rangelst.hxx"
 #include "rangenam.hxx"
 #include "tabopparams.hxx"
@@ -563,6 +564,8 @@ public:
 
     SC_DLLPUBLIC void  InitDrawLayer( SfxObjectShell* pDocShell = nullptr );
 
+    SC_DLLPUBLIC ScInterpreterContext     GetNonThreadedContext() const;
+
     SC_DLLPUBLIC sfx2::LinkManager*       GetLinkManager();
     SC_DLLPUBLIC const sfx2::LinkManager* GetLinkManager() const;
 
@@ -1118,10 +1121,10 @@ public:
     SC_DLLPUBLIC void                         GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab,
                                                                sal_uInt32& rFormat ) const;
     sal_uInt32                                GetNumberFormat( const ScRange& rRange ) const;
-    SC_DLLPUBLIC sal_uInt32                   GetNumberFormat( const ScAddress& ) const;
+    SC_DLLPUBLIC sal_uInt32                   GetNumberFormat( const ScInterpreterContext& rContext, const ScAddress& ) const;
     void                                      SetNumberFormat( const ScAddress& rPos, sal_uInt32 nNumberFormat );
 
-    void                                      GetNumberFormatInfo( short& nType, sal_uLong& nIndex, const ScAddress& rPos ) const;
+    void                                      GetNumberFormatInfo( const ScInterpreterContext& rContext, short& nType, sal_uLong& nIndex, const ScAddress& rPos ) const;
     SC_DLLPUBLIC const ScFormulaCell*         GetFormulaCell( const ScAddress& rPos ) const;
     SC_DLLPUBLIC ScFormulaCell*               GetFormulaCell( const ScAddress& rPos );
     SC_DLLPUBLIC void                         GetFormula( SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rFormula ) const;
@@ -2056,7 +2059,7 @@ public:
     void SC_DLLPUBLIC SetFormulaResults( const ScAddress& rTopPos, const double* pResults, size_t nLen );
     void SC_DLLPUBLIC SetFormulaResults( const ScAddress& rTopPos, const formula::FormulaConstTokenRef* pResults, size_t nLen );
 
-    ScDocumentThreadSpecific CalculateInColumnInThread( const ScAddress& rTopPos, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal);
+    ScDocumentThreadSpecific CalculateInColumnInThread( const ScInterpreterContext& rContext, const ScAddress& rTopPos, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal);
     void HandleStuffAfterParallelCalculation( const ScAddress& rTopPos, size_t nLen );
 
     /**
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index 40fe21598e28..0185e2629010 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -30,7 +30,7 @@
 #include <svl/listener.hxx>
 
 #include "types.hxx"
-
+#include "interpretercontext.hxx"
 #include "formularesult.hxx"
 
 namespace sc {
@@ -150,7 +150,7 @@ public:
                         SCITP_FROM_ITERATION,
                         SCITP_CLOSE_ITERATION_CIRCLE
                     };
-    void            InterpretTail( ScInterpretTailParameter );
+                    void InterpretTail( const ScInterpreterContext&, ScInterpretTailParameter );
 
     void            HandleStuffAfterParallelCalculation();
 
diff --git a/sc/inc/interpretercontext.hxx b/sc/inc/interpretercontext.hxx
new file mode 100644
index 000000000000..cbf05349ca5f
--- /dev/null
+++ b/sc/inc/interpretercontext.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_SC_INC_INTERPRETERCONTEXT_HXX
+#define INCLUDED_SC_INC_INTERPRETERCONTEXT_HXX
+
+class ScDocument;
+class SvNumberFormatter;
+
+struct ScInterpreterContext
+{
+    const ScDocument& mrDoc;
+    SvNumberFormatter* mpFormatter;
+
+    ScInterpreterContext(const ScDocument& rDoc, SvNumberFormatter* pFormatter) :
+        mrDoc(rDoc),
+        mpFormatter(pFormatter)
+    {
+    }
+
+    ~ScInterpreterContext()
+    {
+    }
+
+    SvNumberFormatter* GetFormatTable() const
+    {
+        return mpFormatter;
+    }
+};
+
+#endif // INCLUDED_SC_INC_INTERPRETERCONTEXT_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 9b04a4d019a4..1f77ae4d2e39 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -116,6 +116,7 @@ class ScRangeName;
 class ScDBData;
 class ScDocumentImport;
 class ScHint;
+struct ScInterpreterContext;
 
 class ScColumnsRange final
 {
@@ -672,7 +673,7 @@ public:
     const ScPatternAttr*    GetPattern( SCCOL nCol, SCROW nRow ) const;
     const ScPatternAttr*    GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow ) const;
 
-    sal_uInt32 GetNumberFormat( const ScAddress& rPos ) const;
+    sal_uInt32 GetNumberFormat( const ScInterpreterContext& rContext, const ScAddress& rPos ) const;
     sal_uInt32 GetNumberFormat( SCCOL nCol, SCROW nRow ) const;
     sal_uInt32 GetNumberFormat( SCCOL nCol, SCROW nStartRow, SCROW nEndRow ) const;
 
@@ -997,7 +998,7 @@ public:
     void SetFormulaResults( SCCOL nCol, SCROW nRow, const double* pResults, size_t nLen );
     void SetFormulaResults( SCCOL nCol, SCROW nRow, const formula::FormulaConstTokenRef* pResults, size_t nLen );
 
-    void CalculateInColumnInThread( SCCOL nCol, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal);
+    void CalculateInColumnInThread( const ScInterpreterContext& rContext, SCCOL nCol, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal);
     void HandleStuffAfterParallelCalculation( SCCOL nCol, SCROW nRow, size_t nLen);
 
     /**
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 48a551462c60..11bd7010ce32 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -418,9 +418,9 @@ sal_uInt32 ScColumn::GetNumberFormat( SCROW nStartRow, SCROW nEndRow ) const
     return nFormat;
 }
 
-sal_uInt32 ScColumn::GetNumberFormat( SCROW nRow ) const
+sal_uInt32 ScColumn::GetNumberFormat( const ScInterpreterContext& rContext, SCROW nRow ) const
 {
-    return pAttrArray->GetPattern( nRow )->GetNumberFormat( pDocument->GetFormatTable() );
+    return pAttrArray->GetPattern( nRow )->GetNumberFormat( rContext.GetFormatTable() );
 }
 
 SCROW ScColumn::ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData& rMark, ScEditDataArray* pDataArray, bool* const pIsChanged )
@@ -1151,7 +1151,7 @@ void ScColumn::CopyStaticToDocument(
     // Dont' forget to copy the number formats over.  Charts may reference them.
     for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
     {
-        sal_uInt32 nNumFmt = GetNumberFormat(nRow);
+        sal_uInt32 nNumFmt = GetNumberFormat(pDocument->GetNonThreadedContext(), nRow);
         SvNumberFormatterMergeMap::const_iterator itNum = rMap.find(nNumFmt);
         if (itNum != rMap.end())
             nNumFmt = itNum->second;
@@ -2887,7 +2887,7 @@ public:
 
     void operator() (size_t nRow, ScFormulaCell* pCell)
     {
-        sal_uInt32 nFormat = mrCol.GetNumberFormat(nRow);
+        sal_uInt32 nFormat = mrCol.GetNumberFormat(mrCol.GetDoc().GetNonThreadedContext(), nRow);
         if( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
             // Non-default number format is set.
             pCell->SetNeedNumberFormat(false);
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 705b5ed83ae5..f436d4b11bea 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2877,8 +2877,10 @@ void ScColumn::SetFormulaResults( SCROW nRow, const formula::FormulaConstTokenRe
     }
 }
 
-void ScColumn::CalculateInThread( SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal)
+void ScColumn::CalculateInThread( const ScInterpreterContext& rContext, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal)
 {
+    assert(pDocument->mbThreadedGroupCalcInProgress);
+
     sc::CellStoreType::position_type aPos = maCells.position(nRow);
     sc::CellStoreType::iterator it = aPos.first;
     if (it->type != sc::element_type_formula)
@@ -2901,8 +2903,7 @@ void ScColumn::CalculateInThread( SCROW nRow, size_t nLen, unsigned nThisThread,
         ScFormulaCell& rCell = **itCell;
         // Here we don't call IncInterpretLevel() and DecInterpretLevel() as this call site is
         // always in a threaded calculation.
-        assert(pDocument->mbThreadedGroupCalcInProgress);
-        rCell.InterpretTail(ScFormulaCell::SCITP_NORMAL);
+        rCell.InterpretTail(rContext, ScFormulaCell::SCITP_NORMAL);
     }
 }
 
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 646210a8e679..9a5a57205436 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -1700,7 +1700,7 @@ bool ScColumn::ParseString(
     if (!aParam.mpNumFormatter)
         aParam.mpNumFormatter = pDocument->GetFormatTable();
 
-    nIndex = nOldIndex = GetNumberFormat( nRow );
+    nIndex = nOldIndex = GetNumberFormat( pDocument->GetNonThreadedContext(), nRow );
     if ( rString.getLength() > 1
             && aParam.mpNumFormatter->GetType(nIndex) != css::util::NumberFormat::TEXT )
         cFirstChar = rString[0];
@@ -1922,7 +1922,7 @@ void ScColumn::SetFormula( SCROW nRow, const ScTokenArray& rArray, formula::Form
 
     sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
     ScFormulaCell* pCell = new ScFormulaCell(pDocument, aPos, rArray, eGram);
-    sal_uInt32 nCellFormat = GetNumberFormat(nRow);
+    sal_uInt32 nCellFormat = GetNumberFormat(pDocument->GetNonThreadedContext(), nRow);
     if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
         pCell->SetNeedNumberFormat(true);
     it = maCells.set(it, nRow, pCell);
@@ -1939,7 +1939,7 @@ void ScColumn::SetFormula( SCROW nRow, const OUString& rFormula, formula::Formul
 
     sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
     ScFormulaCell* pCell = new ScFormulaCell(pDocument, aPos, rFormula, eGram);
-    sal_uInt32 nCellFormat = GetNumberFormat(nRow);
+    sal_uInt32 nCellFormat = GetNumberFormat(pDocument->GetNonThreadedContext(), nRow);
     if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
         pCell->SetNeedNumberFormat(true);
     it = maCells.set(it, nRow, pCell);
@@ -1954,7 +1954,7 @@ ScFormulaCell* ScColumn::SetFormulaCell(
     SCROW nRow, ScFormulaCell* pCell, sc::StartListeningType eListenType )
 {
     sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
-    sal_uInt32 nCellFormat = GetNumberFormat(nRow);
+    sal_uInt32 nCellFormat = GetNumberFormat(pDocument->GetNonThreadedContext(), nRow);
     if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
         pCell->SetNeedNumberFormat(true);
     it = maCells.set(it, nRow, pCell);
@@ -1971,7 +1971,7 @@ void ScColumn::SetFormulaCell(
     sc::StartListeningType eListenType )
 {
     rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
-    sal_uInt32 nCellFormat = GetNumberFormat(nRow);
+    sal_uInt32 nCellFormat = GetNumberFormat(pDocument->GetNonThreadedContext(), nRow);
     if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
         pCell->SetNeedNumberFormat(true);
     rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pCell);
@@ -2002,7 +2002,7 @@ bool ScColumn::SetFormulaCells( SCROW nRow, std::vector<ScFormulaCell*>& rCells
         for (size_t i = 0, n = rCells.size(); i < n; ++i)
         {
             SCROW nThisRow = nRow + i;
-            sal_uInt32 nFmt = GetNumberFormat(nThisRow);
+            sal_uInt32 nFmt = GetNumberFormat(pDocument->GetNonThreadedContext(), nThisRow);
             if ((nFmt % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
                 rCells[i]->SetNeedNumberFormat(true);
         }
@@ -2055,7 +2055,7 @@ class FilterEntriesHandler
     {
         SvNumberFormatter* pFormatter = mrColumn.GetDoc().GetFormatTable();
         OUString aStr;
-        sal_uLong nFormat = mrColumn.GetNumberFormat(nRow);
+        sal_uLong nFormat = mrColumn.GetNumberFormat(mrColumn.GetDoc().GetNonThreadedContext(), nRow);
         ScCellFormat::GetInputString(rCell, nFormat, aStr, *pFormatter, &mrColumn.GetDoc());
 
         if (rCell.hasString())
@@ -2543,7 +2543,7 @@ void ScColumn::GetString( SCROW nRow, OUString& rString ) const
     if (aCell.meType == CELLTYPE_FORMULA)
         aCell.mpFormula->MaybeInterpret();
 
-    sal_uLong nFormat = GetNumberFormat(nRow);
+    sal_uLong nFormat = GetNumberFormat(pDocument->GetNonThreadedContext(), nRow);
     Color* pColor = nullptr;
     ScCellFormat::GetString(aCell, nFormat, rString, &pColor, *(pDocument->GetFormatTable()), pDocument);
 }
@@ -2564,7 +2564,7 @@ double* ScColumn::GetValueCell( SCROW nRow )
 void ScColumn::GetInputString( SCROW nRow, OUString& rString ) const
 {
     ScRefCellValue aCell = GetCellValue(nRow);
-    sal_uLong nFormat = GetNumberFormat(nRow);
+    sal_uLong nFormat = GetNumberFormat(pDocument->GetNonThreadedContext(), nRow);
     ScCellFormat::GetInputString(aCell, nFormat, rString, *(pDocument->GetFormatTable()), pDocument);
 }
 
diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx
index 358774153027..fa7f9dfb8c05 100644
--- a/sc/source/core/data/dociter.cxx
+++ b/sc/source/core/data/dociter.cxx
@@ -262,14 +262,14 @@ bool ScValueIterator::GetThis(double& rValue, FormulaError& rErr)
     }
 }
 
-void ScValueIterator::GetCurNumFmtInfo( short& nType, sal_uLong& nIndex )
+void ScValueIterator::GetCurNumFmtInfo( const ScInterpreterContext& rContext, short& nType, sal_uLong& nIndex )
 {
     if (!bNumValid && mnTab < pDoc->GetTableCount())
     {
         SCROW nCurRow = GetRow();
         const ScColumn* pCol = &(pDoc->maTabs[mnTab])->aCol[mnCol];
-        nNumFmtIndex = pCol->GetNumberFormat(nCurRow);
-        nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
+        nNumFmtIndex = pCol->GetNumberFormat(rContext, nCurRow);
+        nNumFmtType = rContext.GetFormatTable()->GetType( nNumFmtIndex );
         bNumValid = true;
     }
 
@@ -334,11 +334,12 @@ bool ScDBQueryDataIterator::IsQueryValid(
     return rDoc.maTabs[nTab]->ValidQuery(nRow, rParam, pCell);
 }
 
-ScDBQueryDataIterator::DataAccessInternal::DataAccessInternal(ScDBQueryParamInternal* pParam, ScDocument* pDoc)
+ScDBQueryDataIterator::DataAccessInternal::DataAccessInternal(ScDBQueryParamInternal* pParam, ScDocument* pDoc, const ScInterpreterContext& rContext)
     : DataAccess()
     , mpCells(nullptr)
     , mpParam(pParam)
     , mpDoc(pDoc)
+    , mrContext(rContext)
     , pAttrArray(nullptr)
     , nNumFormat(0) // Initialized in GetNumberFormat
     , nNumFmtIndex(0)
@@ -432,7 +433,7 @@ bool ScDBQueryDataIterator::DataAccessInternal::getCurrent(Value& rValue)
                         rValue.mfValue = aCell.mpFormula->GetValue();
                         rValue.mbIsNumber = true;
                         mpDoc->GetNumberFormatInfo(
-                            nNumFmtType, nNumFmtIndex, ScAddress(nCol, nRow, nTab));
+                            mrContext, nNumFmtType, nNumFmtIndex, ScAddress(nCol, nRow, nTab));
                         rValue.mnError = aCell.mpFormula->GetErrCode();
                         return true; // Found it!
                     }
@@ -744,7 +745,7 @@ ScDBQueryDataIterator::Value::Value() :
     ::rtl::math::setNan(&mfValue);
 }
 
-ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument* pDocument, ScDBQueryParamBase* pParam) :
+ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument* pDocument, const ScInterpreterContext& rContext, ScDBQueryParamBase* pParam) :
     mpParam (pParam)
 {
     switch (mpParam->GetType())
@@ -752,7 +753,7 @@ ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument* pDocument, ScDBQueryPar
         case ScDBQueryParamBase::INTERNAL:
         {
             ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pParam);
-            mpData.reset(new DataAccessInternal(p, pDocument));
+            mpData.reset(new DataAccessInternal(p, pDocument, rContext));
         }
         break;
         case ScDBQueryParamBase::MATRIX:
@@ -1046,10 +1047,11 @@ bool ScCellIterator::next()
     return getCurrent();
 }
 
-ScQueryCellIterator::ScQueryCellIterator(ScDocument* pDocument, SCTAB nTable,
+ScQueryCellIterator::ScQueryCellIterator(ScDocument* pDocument, const ScInterpreterContext& rContext, SCTAB nTable,
              const ScQueryParam& rParam, bool bMod ) :
     mpParam(new ScQueryParam(rParam)),
     pDoc( pDocument ),
+    mrContext( rContext ),
     nTab( nTable),
     nStopOnMismatch( nStopOnMismatchDisabled ),
     nTestEqualCondition( nTestEqualConditionDisabled ),
@@ -1681,7 +1683,7 @@ bool ScQueryCellIterator::BinarySearch()
         if (aPos.first->type == sc::element_type_string || aPos.first->type == sc::element_type_edittext)
         {
             aCell = sc::toRefCell(aPos.first, aPos.second);
-            sal_uLong nFormat = pCol->GetNumberFormat(nRow);
+            sal_uLong nFormat = pCol->GetNumberFormat(mrContext, nRow);
             OUString aCellStr;
             ScCellFormat::GetInputString(aCell, nFormat, aCellStr, rFormatter, pDoc);
             sal_Int32 nTmp = pCollator->compareString(aCellStr, rEntry.GetQueryItem().maString.getString());
@@ -1715,7 +1717,7 @@ bool ScQueryCellIterator::BinarySearch()
     aCell = aCellData.first;
     if (aCell.hasString())
     {
-        sal_uLong nFormat = pCol->GetNumberFormat(aCellData.second);
+        sal_uLong nFormat = pCol->GetNumberFormat(mrContext, aCellData.second);
         OUString aStr;
         ScCellFormat::GetInputString(aCell, nFormat, aStr, rFormatter, pDoc);
         aLastInRangeString = aStr;
@@ -1814,7 +1816,7 @@ bool ScQueryCellIterator::BinarySearch()
         else if (bStr && bByString)
         {
             OUString aCellStr;
-            sal_uLong nFormat = pCol->GetNumberFormat(aCellData.second);
+            sal_uLong nFormat = pCol->GetNumberFormat(mrContext, aCellData.second);
             ScCellFormat::GetInputString(aCell, nFormat, aCellStr, rFormatter, pDoc);
 
             nRes = pCollator->compareString(aCellStr, rEntry.GetQueryItem().maString.getString());
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 283c082199b2..b15ee591a7e2 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -502,6 +502,7 @@ void ScDocument::InitClipPtrs( ScDocument* pSourceDoc )
 
 SvNumberFormatter* ScDocument::GetFormatTable() const
 {
+    assert(!mbThreadedGroupCalcInProgress);
     return mxPoolHelper->GetFormTable();
 }
 
diff --git a/sc/source/core/data/documen8.cxx b/sc/source/core/data/documen8.cxx
index b29de4004c90..8bf1de3fb191 100644
--- a/sc/source/core/data/documen8.cxx
+++ b/sc/source/core/data/documen8.cxx
@@ -427,7 +427,7 @@ void ScDocument::SetFormulaResults(
     pTab->SetFormulaResults(rTopPos.Col(), rTopPos.Row(), pResults, nLen);
 }
 
-ScDocumentThreadSpecific ScDocument::CalculateInColumnInThread( const ScAddress& rTopPos, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal)
+ScDocumentThreadSpecific ScDocument::CalculateInColumnInThread( const ScInterpreterContext& rContext, const ScAddress& rTopPos, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal)
 {
     ScTable* pTab = FetchTable(rTopPos.Tab());
     if (!pTab)
@@ -436,7 +436,7 @@ ScDocumentThreadSpecific ScDocument::CalculateInColumnInThread( const ScAddress&
     assert(mbThreadedGroupCalcInProgress);
 
     maThreadSpecific.SetupFromNonThreadedData(maNonThreaded);
-    pTab->CalculateInColumnInThread(rTopPos.Col(), rTopPos.Row(), nLen, nThisThread, nThreadsTotal);
+    pTab->CalculateInColumnInThread(rContext, rTopPos.Col(), rTopPos.Row(), nLen, nThisThread, nThreadsTotal);
 
     assert(mbThreadedGroupCalcInProgress);
 
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 185115ac8ad7..f15107bc3fe7 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -3702,13 +3702,13 @@ sal_uInt32 ScDocument::GetNumberFormat( const ScRange& rRange ) const
     return nFormat;
 }
 
-sal_uInt32 ScDocument::GetNumberFormat( const ScAddress& rPos ) const
+sal_uInt32 ScDocument::GetNumberFormat( const ScInterpreterContext& rContext, const ScAddress& rPos ) const
 {
     SCTAB nTab = rPos.Tab();
     if (!TableExists(nTab))
         return 0;
 
-    return maTabs[nTab]->GetNumberFormat( rPos );
+    return maTabs[nTab]->GetNumberFormat( rContext, rPos );
 }
 
 void ScDocument::SetNumberFormat( const ScAddress& rPos, sal_uInt32 nNumberFormat )
@@ -3720,14 +3720,14 @@ void ScDocument::SetNumberFormat( const ScAddress& rPos, sal_uInt32 nNumberForma
     maTabs[nTab]->SetNumberFormat(rPos.Col(), rPos.Row(), nNumberFormat);
 }
 
-void ScDocument::GetNumberFormatInfo( short& nType, sal_uLong& nIndex,
+void ScDocument::GetNumberFormatInfo( const ScInterpreterContext& rContext, short& nType, sal_uLong& nIndex,
             const ScAddress& rPos ) const
 {
     SCTAB nTab = rPos.Tab();
     if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
     {
-        nIndex = maTabs[nTab]->GetNumberFormat( rPos );
-        nType = GetFormatTable()->GetType( nIndex );
+        nIndex = maTabs[nTab]->GetNumberFormat( rContext, rPos );
+        nType = rContext.GetFormatTable()->GetType( nIndex );
     }
     else
     {
@@ -6769,6 +6769,13 @@ ScMutationGuard::~ScMutationGuard()
 #endif
 }
 
+ScInterpreterContext ScDocument::GetNonThreadedContext() const
+{
+    // GetFormatTable() asserts that we are not in a threaded calculation
+    ScInterpreterContext aResult(*this, GetFormatTable());
+    return aResult;
+}
+
 thread_local ScDocumentThreadSpecific ScDocument::maThreadSpecific;
 
 ScRecursionHelper& ScDocument::GetRecursionHelper()
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index bc6fd157e34b..2d6d49bc191a 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -1528,10 +1528,10 @@ void ScFormulaCell::Interpret()
         bool bGroupInterpreted = InterpretFormulaGroup();
         aDC.leaveGroup();
         if (!bGroupInterpreted)
-            InterpretTail( SCITP_NORMAL);
+            InterpretTail( pDocument->GetNonThreadedContext(), SCITP_NORMAL);
 #else
         if (!InterpretFormulaGroup())
-            InterpretTail( SCITP_NORMAL);
+            InterpretTail( pDocument->GetNonThreadedContext(), SCITP_NORMAL);
 #endif
         pDocument->DecInterpretLevel();
     }
@@ -1595,8 +1595,8 @@ void ScFormulaCell::Interpret()
                     bResumeIteration = false;
                     // Close circle once.
                     pDocument->IncInterpretLevel();
-                    rRecursionHelper.GetList().back().pCell->InterpretTail(
-                            SCITP_CLOSE_ITERATION_CIRCLE);
+                    rRecursionHelper.GetList().back().pCell->InterpretTail( pDocument->GetNonThreadedContext(),
+                                                                            SCITP_CLOSE_ITERATION_CIRCLE);
                     pDocument->DecInterpretLevel();
                     // Start at 1, init things.
                     rRecursionHelper.StartIteration();
@@ -1627,7 +1627,7 @@ void ScFormulaCell::Interpret()
                         {
                             (*aIter).aPreviousResult = pIterCell->aResult;
                             pDocument->IncInterpretLevel();
-                            pIterCell->InterpretTail( SCITP_FROM_ITERATION);
+                            pIterCell->InterpretTail( pDocument->GetNonThreadedContext(), SCITP_FROM_ITERATION);
                             pDocument->DecInterpretLevel();
                         }
                         rDone = rDone && !pIterCell->IsDirtyOrInTableOpDirty();
@@ -1699,7 +1699,7 @@ void ScFormulaCell::Interpret()
                         if (pCell->IsDirtyOrInTableOpDirty())
                         {
                             pDocument->IncInterpretLevel();
-                            pCell->InterpretTail( SCITP_NORMAL);
+                            pCell->InterpretTail( pDocument->GetNonThreadedContext(), SCITP_NORMAL);
                             pDocument->DecInterpretLevel();
                             if (!pCell->IsDirtyOrInTableOpDirty() && !pCell->IsIterCell())
                                 pCell->bRunning = (*aIter).bOldRunning;
@@ -1748,7 +1748,7 @@ class StackCleaner
 };
 }
 
-void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam )
+void ScFormulaCell::InterpretTail( const ScInterpreterContext& rContext, ScInterpretTailParameter eTailParam )
 {
     RecursionCounter aRecursionCounter( pDocument->GetRecursionHelper(), this);
     nSeenInIteration = pDocument->GetRecursionHelper().GetIteration();
@@ -1775,7 +1775,7 @@ void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam )
 
     if( pCode->GetCodeLen() && pDocument )
     {
-        ScInterpreter* pInterpreter = new ScInterpreter( this, pDocument, aPos, *pCode );
+        ScInterpreter* pInterpreter = new ScInterpreter( this, pDocument, rContext, aPos, *pCode );
         StackCleaner aStackCleaner(pInterpreter);
         FormulaError nOldErrCode = aResult.GetResultError();
         if ( nSeenInIteration == 0 )
@@ -1981,7 +1981,7 @@ void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam )
             }
 
             if (bSetFormat && (bForceNumberFormat || ((nFormatIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0)))
-                nFormatIndex = ScGlobal::GetStandardFormat(*pDocument->GetFormatTable(),
+                nFormatIndex = ScGlobal::GetStandardFormat(*rContext.GetFormatTable(),
                         nFormatIndex, nFormatType);
 
             // Do not replace a General format (which was the reason why
@@ -2168,7 +2168,7 @@ void ScFormulaCell::HandleStuffAfterParallelCalculation()
         if ( !pCode->IsRecalcModeAlways() )
             pDocument->RemoveFromFormulaTree( this );
 
-        ScInterpreter* pInterpreter = new ScInterpreter( this, pDocument, aPos, *pCode );
+        ScInterpreter* pInterpreter = new ScInterpreter( this, pDocument, pDocument->GetNonThreadedContext(), aPos, *pCode );
         StackCleaner aStackCleaner(pInterpreter);
 
         switch (pInterpreter->GetVolatileType())
@@ -4328,6 +4328,9 @@ bool ScFormulaCell::InterpretFormulaGroup()
 
     static const bool bThreadingRequested = std::getenv("CPU_THREADED_CALCULATION");
 
+    // To temporarilu use threading for sc unit tests regardless of the size of the formula group,
+    // add the condition !std::getenv("LO_TESTNAME") below (with &&), and run with
+    // CPU_THREADED_CALCULATION=yes
     if (GetWeight() < ScInterpreter::GetGlobalConfig().mnOpenCLMinimumFormulaGroupSize)
     {
         mxGroup->meCalcState = sc::GroupCalcDisabled;
@@ -4367,6 +4370,7 @@ bool ScFormulaCell::InterpretFormulaGroup()
             const unsigned mnThisThread;
             const unsigned mnThreadsTotal;
             ScDocument* mpDocument;
+            SvNumberFormatter* mpFormatter;
             const ScAddress& mrTopPos;
             SCROW mnLength;
 
@@ -4375,12 +4379,14 @@ bool ScFormulaCell::InterpretFormulaGroup()
                      unsigned nThisThread,
                      unsigned nThreadsTotal,
                      ScDocument* pDocument,
+                     SvNumberFormatter* pFormatter,
                      const ScAddress& rTopPos,
                      SCROW nLength) :
                 comphelper::ThreadTask(rTag),
                 mnThisThread(nThisThread),
                 mnThreadsTotal(nThreadsTotal),
                 mpDocument(pDocument),
+                mpFormatter(pFormatter),
                 mrTopPos(rTopPos),
                 mnLength(nLength)
             {
@@ -4388,11 +4394,18 @@ bool ScFormulaCell::InterpretFormulaGroup()
 
             virtual void doWork() override
             {
-                mpDocument->CalculateInColumnInThread(mrTopPos, mnLength, mnThisThread, mnThreadsTotal).MergeBackIntoNonThreadedData(mpDocument->maNonThreaded);
+                std::unique_ptr<SvNumberFormatter> pFormatterForThisThread
+                    (new SvNumberFormatter(mpFormatter->GetComponentContext(),
+                                           mpFormatter->GetLanguage()));
+                ScInterpreterContext aContext(*mpDocument, pFormatterForThisThread.get());
+
+                mpDocument->CalculateInColumnInThread(aContext, mrTopPos, mnLength, mnThisThread, mnThreadsTotal).MergeBackIntoNonThreadedData(mpDocument->maNonThreaded);
             }
 
         };
 
+        SvNumberFormatter* pNonThreadedFormatter = pDocument->GetNonThreadedContext().GetFormatTable();
+
         comphelper::ThreadPool& rThreadPool(comphelper::ThreadPool::getSharedOptimalPool());
         sal_Int32 nThreadCount = rThreadPool.getWorkerCount();
 
@@ -4408,7 +4421,7 @@ bool ScFormulaCell::InterpretFormulaGroup()
             std::shared_ptr<comphelper::ThreadTaskTag> aTag = comphelper::ThreadPool::createThreadTaskTag();
             for (int i = 0; i < nThreadCount; ++i)
             {
-                rThreadPool.pushTask(new Executor(aTag, i, nThreadCount, pDocument, mxGroup->mpTopCell->aPos, mxGroup->mnLength));
+                rThreadPool.pushTask(new Executor(aTag, i, nThreadCount, pDocument, pNonThreadedFormatter, mxGroup->mpTopCell->aPos, mxGroup->mnLength));
             }
 
             SAL_INFO("sc.threaded", "Joining threads");
@@ -4606,14 +4619,14 @@ bool ScFormulaCell::InterpretInvariantFormulaGroup()
 
         ScCompiler aComp(pDocument, aPos, aCode, pDocument->GetGrammar());
         aComp.CompileTokenArray(); // Create RPN token array.
-        ScInterpreter aInterpreter(this, pDocument, aPos, aCode);
+        ScInterpreter aInterpreter(this, pDocument, pDocument->GetNonThreadedContext(), aPos, aCode);
         aInterpreter.Interpret();
         aResult.SetToken(aInterpreter.GetResultToken().get());
     }
     else
     {
         // Formula contains no references.
-        ScInterpreter aInterpreter(this, pDocument, aPos, *pCode);
+        ScInterpreter aInterpreter(this, pDocument, pDocument->GetNonThreadedContext(), aPos, *pCode);
         aInterpreter.Interpret();
         aResult.SetToken(aInterpreter.GetResultToken().get());
     }
diff --git a/sc/source/core/data/simpleformulacalc.cxx b/sc/source/core/data/simpleformulacalc.cxx
index b1e0f65f9ff7..859114515e5c 100644
--- a/sc/source/core/data/simpleformulacalc.cxx
+++ b/sc/source/core/data/simpleformulacalc.cxx
@@ -44,7 +44,7 @@ void ScSimpleFormulaCalculator::Calculate()
         return;
 
     mbCalculated = true;
-    ScInterpreter aInt(nullptr, mpDoc, maAddr, *mpCode.get());
+    ScInterpreter aInt(nullptr, mpDoc, mpDoc->GetNonThreadedContext(), maAddr, *mpCode.get());
 
     std::unique_ptr<sfx2::LinkManager> pNewLinkMgr( new sfx2::LinkManager(mpDoc->GetDocumentShell()) );
     aInt.SetLinkManager( pNewLinkMgr.get() );
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 961b2f443568..e43ab0efc7ac 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2338,12 +2338,12 @@ void ScTable::SetFormulaResults(
     aCol[nCol].SetFormulaResults(nRow, pResults, nLen);
 }
 
-void ScTable::CalculateInColumnInThread( SCCOL nCol, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal)
+void ScTable::CalculateInColumnInThread( const ScInterpreterContext& rContext, SCCOL nCol, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal)
 {
     if (!ValidCol(nCol))
         return;
 
-    aCol[nCol].CalculateInThread( nRow, nLen, nThisThread, nThreadsTotal );
+    aCol[nCol].CalculateInThread( rContext, nRow, nLen, nThisThread, nThreadsTotal );
 }
 
 void ScTable::HandleStuffAfterParallelCalculation( SCCOL nCol, SCROW nRow, size_t nLen)
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 60e05b323be9..56be6df03201 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -1899,17 +1899,17 @@ const SfxPoolItem* ScTable::GetAttr( SCCOL nCol, SCROW nRow, sal_uInt16 nWhich )
         return nullptr;
 }
 
-sal_uInt32 ScTable::GetNumberFormat( const ScAddress& rPos ) const
+sal_uInt32 ScTable::GetNumberFormat( const ScInterpreterContext& rContext, const ScAddress& rPos ) const
 {
     return ValidColRow(rPos.Col(),rPos.Row()) ?
-        aCol[rPos.Col()].GetNumberFormat( rPos.Row() ) :
+        aCol[rPos.Col()].GetNumberFormat( rContext, rPos.Row() ) :
         0;
 }
 
 sal_uInt32 ScTable::GetNumberFormat( SCCOL nCol, SCROW nRow ) const
 {
     if (ValidColRow(nCol,nRow))
-        return aCol[nCol].GetNumberFormat( nRow );
+        return aCol[nCol].GetNumberFormat( pDocument->GetNonThreadedContext(), nRow );
     else
         return 0;
 }
diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx
index 2579545c4c91..45927fe4de8f 100644
--- a/sc/source/core/data/table4.cxx
+++ b/sc/source/core/data/table4.cxx
@@ -1380,14 +1380,14 @@ void ScTable::FillAutoSimple(
                         return;
                     }
                     bBooleanCell = (pDocument->GetFormatTable()->GetType(
-                                aCol[rCol].GetNumberFormat( nSource)) == css::util::NumberFormat::LOGICAL);
+                                aCol[rCol].GetNumberFormat( pDocument->GetNonThreadedContext(), nSource)) == css::util::NumberFormat::LOGICAL);
 
                 }
                 else                // rInner&:=nCol, rOuter&:=nRow
                 {
                     aSrcCell = aCol[nSource].GetCellValue(rRow);
                     bBooleanCell = (pDocument->GetFormatTable()->GetType(
-                                aCol[nSource].GetNumberFormat( rRow)) == css::util::NumberFormat::LOGICAL);
+                                aCol[nSource].GetNumberFormat( pDocument->GetNonThreadedContext(), rRow)) == css::util::NumberFormat::LOGICAL);
                 }
 
                 bGetCell = false;
diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx
index 9917e943fe59..9c754c2e9386 100644
--- a/sc/source/core/inc/interpre.hxx
+++ b/sc/source/core/inc/interpre.hxx
@@ -29,6 +29,7 @@
 #include <sfx2/linkmgr.hxx>
 #include <scdll.hxx>
 #include <scdllapi.h>
+#include <interpretercontext.hxx>
 #include <types.hxx>
 #include <externalrefmgr.hxx>
 #include <calcconfig.hxx>
@@ -198,6 +199,7 @@ private:
     formula::FormulaTokenIterator aCode;
     ScAddress   aPos;
     ScTokenArray& rArr;
+    const ScInterpreterContext& mrContext;
     ScDocument* pDok;
     sfx2::LinkManager* mpLinkManager;
     svl::SharedStringPool& mrStrPool;
@@ -988,7 +990,7 @@ private:
     double GetTInv( double fAlpha, double fSize, int nType );
 
 public:
-    ScInterpreter( ScFormulaCell* pCell, ScDocument* pDoc,
+    ScInterpreter( ScFormulaCell* pCell, ScDocument* pDoc, const ScInterpreterContext& rContext,
                     const ScAddress&, ScTokenArray& );
     ~ScInterpreter();
 
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 0730bae98a4d..f637ab5753bc 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -251,7 +251,7 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
 
         ScCompiler aComp(&rDoc, aTmpPos, aCode2);
         aComp.CompileTokenArray();
-        ScInterpreter aInterpreter(pDest, &rDoc, aTmpPos, aCode2);
+        ScInterpreter aInterpreter(pDest, &rDoc, rDoc.GetNonThreadedContext(), aTmpPos, aCode2);
         aInterpreter.Interpret();
         aResults.push_back(aInterpreter.GetResultToken());
     } // for loop end (xGroup->mnLength)
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index 157c8a2dcedd..9fac42814541 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -3550,7 +3550,7 @@ void ScInterpreter::ScMin( bool bTextAsZero )
                 {
                     if (nMin > nVal)
                         nMin = nVal;
-                    aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
+                    aValIter.GetCurNumFmtInfo( mrContext, nFuncFmtType, nFuncFmtIndex );
                     while ((nErr == FormulaError::NONE) && aValIter.GetNext(nVal, nErr))
                     {
                         if (nMin > nVal)
@@ -3707,7 +3707,7 @@ void ScInterpreter::ScMax( bool bTextAsZero )
                 {
                     if (nMax < nVal)
                         nMax = nVal;
-                    aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
+                    aValIter.GetCurNumFmtInfo( mrContext, nFuncFmtType, nFuncFmtIndex );
                     while ((nErr == FormulaError::NONE) && aValIter.GetNext(nVal, nErr))
                     {
                         if (nMax < nVal)
@@ -4864,7 +4864,7 @@ void ScInterpreter::ScMatch()
                 rParam.bByRow = false;
                 rParam.nRow2 = nRow1;
                 rEntry.nField = nCol1;
-                ScQueryCellIterator aCellIter(pDok, nTab1, rParam, false);
+                ScQueryCellIterator aCellIter(pDok, mrContext, nTab1, rParam, false);
                 // Advance Entry.nField in Iterator if column changed
                 aCellIter.SetAdvanceQueryParamEntryField( true );
                 if (fTyp == 0.0)
@@ -5343,7 +5343,7 @@ void ScInterpreter::IterateParametersIf( ScIterFuncIf eFunc )
             }
             else
             {
-                ScQueryCellIterator aCellIter(pDok, nTab1, rParam, false);
+                ScQueryCellIterator aCellIter(pDok, mrContext, nTab1, rParam, false);
                 // Increment Entry.nField in iterator when switching to next column.
                 aCellIter.SetAdvanceQueryParamEntryField( true );
                 if ( aCellIter.GetFirst() )
@@ -5605,7 +5605,7 @@ void ScInterpreter::ScCountIf()
                 }
                 else
                 {
-                    ScQueryCellIterator aCellIter(pDok, nTab1, rParam, false);
+                    ScQueryCellIterator aCellIter(pDok, mrContext, nTab1, rParam, false);
                     // Keep Entry.nField in iterator on column change
                     aCellIter.SetAdvanceQueryParamEntryField( true );
                     if ( aCellIter.GetFirst() )
@@ -5898,7 +5898,7 @@ void ScInterpreter::IterateParametersIfs( double(*ResultFunc)( const sc::ParamIf
             }
             else
             {
-                ScQueryCellIterator aCellIter(pDok, nTab1, rParam, false);
+                ScQueryCellIterator aCellIter(pDok, mrContext, nTab1, rParam, false);
                 // Increment Entry.nField in iterator when switching to next column.
                 aCellIter.SetAdvanceQueryParamEntryField( true );
                 if ( aCellIter.GetFirst() )
@@ -6724,7 +6724,7 @@ void ScInterpreter::ScLookup()
     if (rItem.meType == ScQueryEntry::ByString)
         aParam.eSearchType = DetectSearchType(rItem.maString.getString(), pDok);
 
-    ScQueryCellIterator aCellIter(pDok, nTab1, aParam, false);
+    ScQueryCellIterator aCellIter(pDok, mrContext, nTab1, aParam, false);
     SCCOL nC;
     SCROW nR;
     // Advance Entry.nField in iterator upon switching columns if
@@ -7071,7 +7071,7 @@ void ScInterpreter::CalculateLookup(bool bHLookup)
             rEntry.eOp = SC_LESS_EQUAL;
         if ( bHLookup )
         {
-            ScQueryCellIterator aCellIter(pDok, nTab1, aParam, false);
+            ScQueryCellIterator aCellIter(pDok, mrContext, nTab1, aParam, false);
             // advance Entry.nField in Iterator upon switching columns
             aCellIter.SetAdvanceQueryParamEntryField( true );
             if ( bSorted )
@@ -7447,7 +7447,7 @@ void ScInterpreter::DBIterator( ScIterFunc eFunc )
             SetError(FormulaError::NoValue);
             return;
         }
-        ScDBQueryDataIterator aValIter(pDok, pQueryParam.release());
+        ScDBQueryDataIterator aValIter(pDok, mrContext, pQueryParam.release());
         ScDBQueryDataIterator::Value aValue;
         if ( aValIter.GetFirst(aValue) && aValue.mnError == FormulaError::NONE )
         {
@@ -7535,7 +7535,7 @@ void ScInterpreter::ScDBCount()
             // so the source range has to be restricted, like before the introduction
             // of ScDBQueryParamBase.
             p->nCol1 = p->nCol2 = p->mnField;
-            ScQueryCellIterator aCellIter( pDok, nTab, *p, true);
+            ScQueryCellIterator aCellIter( pDok, mrContext, nTab, *p, true);
             if ( aCellIter.GetFirst() )
             {
                 do
@@ -7551,7 +7551,7 @@ void ScInterpreter::ScDBCount()
                 SetError(FormulaError::NoValue);
                 return;
             }
-            ScDBQueryDataIterator aValIter( pDok, pQueryParam.release());
+            ScDBQueryDataIterator aValIter( pDok, mrContext, pQueryParam.release());
             ScDBQueryDataIterator::Value aValue;
             if ( aValIter.GetFirst(aValue) && aValue.mnError == FormulaError::NONE )
             {
@@ -7582,7 +7582,7 @@ void ScInterpreter::ScDBCount2()
         }
         sal_uLong nCount = 0;
         pQueryParam->mbSkipString = false;
-        ScDBQueryDataIterator aValIter( pDok, pQueryParam.release());
+        ScDBQueryDataIterator aValIter( pDok, mrContext, pQueryParam.release());
         ScDBQueryDataIterator::Value aValue;
         if ( aValIter.GetFirst(aValue) && aValue.mnError == FormulaError::NONE )
         {
@@ -7636,7 +7636,7 @@ void ScInterpreter::GetDBStVarParams( double& rVal, double& rValCount )
             SetError(FormulaError::NoValue);
             return;
         }
-        ScDBQueryDataIterator aValIter(pDok, pQueryParam.release());
+        ScDBQueryDataIterator aValIter(pDok, mrContext, pQueryParam.release());
         ScDBQueryDataIterator::Value aValue;
         if (aValIter.GetFirst(aValue) && aValue.mnError == FormulaError::NONE)
         {
@@ -9297,11 +9297,11 @@ utl::SearchParam::SearchType ScInterpreter::DetectSearchType( const OUString& rS
     return utl::SearchParam::SearchType::Normal;
 }
 
-static bool lcl_LookupQuery( ScAddress & o_rResultPos, ScDocument * pDoc,
+static bool lcl_LookupQuery( ScAddress & o_rResultPos, ScDocument * pDoc, const ScInterpreterContext& rContext,
         const ScQueryParam & rParam, const ScQueryEntry & rEntry )
 {
     bool bFound = false;
-    ScQueryCellIterator aCellIter( pDoc, rParam.nTab, rParam, false);
+    ScQueryCellIterator aCellIter( pDoc, rContext, rParam.nTab, rParam, false);
     if (rEntry.eOp != SC_EQUAL)
     {
         // range lookup <= or >=
@@ -9338,7 +9338,7 @@ bool ScInterpreter::LookupQueryWithCache( ScAddress & o_rResultPos,
      * direct lookups here. We could even further attribute volatility per
      * parameter so it would affect only the lookup range parameter. */
     if (!bColumnsMatch || GetVolatileType() != NOT_VOLATILE)
-        bFound = lcl_LookupQuery( o_rResultPos, pDok, rParam, rEntry);
+        bFound = lcl_LookupQuery( o_rResultPos, pDok, mrContext, rParam, rEntry);
     else
     {
         ScRange aLookupRange( rParam.nCol1, rParam.nRow1, rParam.nTab,
@@ -9351,7 +9351,7 @@ bool ScInterpreter::LookupQueryWithCache( ScAddress & o_rResultPos,
         {
             case ScLookupCache::NOT_CACHED :
             case ScLookupCache::CRITERIA_DIFFERENT :
-                bFound = lcl_LookupQuery( o_rResultPos, pDok, rParam, rEntry);
+                bFound = lcl_LookupQuery( o_rResultPos, pDok, mrContext, rParam, rEntry);
                 if (eCacheResult == ScLookupCache::NOT_CACHED)
                     rCache.insert( o_rResultPos, aCriteria, aPos, bFound);
                 break;
diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx
index 50350fac8e85..e62610b1d50b 100644
--- a/sc/source/core/tool/interpr4.cxx
+++ b/sc/source/core/tool/interpr4.cxx
@@ -203,7 +203,7 @@ double ScInterpreter::GetCellValueOrZero( const ScAddress& rPos, ScRefCellValue&
                 if (pFCell->IsValue())
                 {
                     fValue = pFCell->GetValue();
-                    pDok->GetNumberFormatInfo( nCurFmtType, nCurFmtIndex,
+                    pDok->GetNumberFormatInfo( mrContext, nCurFmtType, nCurFmtIndex,
                         rPos );
                 }
                 else
@@ -221,7 +221,7 @@ double ScInterpreter::GetCellValueOrZero( const ScAddress& rPos, ScRefCellValue&
         case CELLTYPE_VALUE:
         {
             fValue = rCell.mfValue;
-            nCurFmtIndex = pDok->GetNumberFormat( rPos );
+            nCurFmtIndex = pDok->GetNumberFormat( mrContext, rPos );
             nCurFmtType = pFormatter->GetType( nCurFmtIndex );
             if ( bCalcAsShown && fValue != 0.0 )
                 fValue = pDok->RoundValueAsShown( fValue, nCurFmtIndex );
@@ -697,7 +697,7 @@ void ScInterpreter::PushCellResultToken( bool bDisplayEmptyAsString,
     {
         bool bInherited = (aCell.meType == CELLTYPE_FORMULA);
         if (pRetTypeExpr && pRetIndexExpr)
-            pDok->GetNumberFormatInfo(*pRetTypeExpr, *pRetIndexExpr, rAddress);
+            pDok->GetNumberFormatInfo(mrContext, *pRetTypeExpr, *pRetIndexExpr, rAddress);
         PushTempToken( new ScEmptyCellToken( bInherited, bDisplayEmptyAsString));
         return;
     }
@@ -2503,7 +2503,7 @@ void ScInterpreter::ScDBGet()
     }
 
     pQueryParam->mbSkipString = false;
-    ScDBQueryDataIterator aValIter(pDok, pQueryParam.release());
+    ScDBQueryDataIterator aValIter(pDok, mrContext, pQueryParam.release());
     ScDBQueryDataIterator::Value aValue;
     if (!aValIter.GetFirst(aValue) || aValue.mnError != FormulaError::NONE)
     {
@@ -3782,18 +3782,19 @@ void ScInterpreter::ScTTT()
     PushError(FormulaError::NoValue);
 }
 
-ScInterpreter::ScInterpreter( ScFormulaCell* pCell, ScDocument* pDoc,
+ScInterpreter::ScInterpreter( ScFormulaCell* pCell, ScDocument* pDoc, const ScInterpreterContext& rContext,
         const ScAddress& rPos, ScTokenArray& r )
     : aCode(r)
     , aPos(rPos)
     , rArr(r)
+    , mrContext(rContext)
     , pDok(pDoc)
     , mpLinkManager(pDok->GetLinkManager())
     , mrStrPool(pDoc->GetSharedStringPool())
     , pJumpMatrix(nullptr)
     , pTokenMatrixMap(nullptr)
     , pMyFormulaCell(pCell)
-    , pFormatter(pDoc->GetFormatTable())
+    , pFormatter(rContext.GetFormatTable())
     , pCur(nullptr)
     , nGlobalError(FormulaError::NONE)
     , sp(0)
diff --git a/sc/source/core/tool/interpr5.cxx b/sc/source/core/tool/interpr5.cxx
index 0fe8cced4c6f..909965676139 100644
--- a/sc/source/core/tool/interpr5.cxx
+++ b/sc/source/core/tool/interpr5.cxx
@@ -3224,7 +3224,7 @@ void ScInterpreter::ScMatRef()
             else
             {
                 // Determine nFuncFmtType type before PushDouble().
-                pDok->GetNumberFormatInfo(nCurFmtType, nCurFmtIndex, aAdr);
+                pDok->GetNumberFormatInfo(mrContext, nCurFmtType, nCurFmtIndex, aAdr);
                 nFuncFmtType = nCurFmtType;
                 nFuncFmtIndex = nCurFmtIndex;
                 PushDouble(nMatVal.fVal);  // handles DoubleError
@@ -3234,7 +3234,7 @@ void ScInterpreter::ScMatRef()
     else
     {
         // Determine nFuncFmtType type before PushDouble().
-        pDok->GetNumberFormatInfo(nCurFmtType, nCurFmtIndex, aAdr);
+        pDok->GetNumberFormatInfo(mrContext, nCurFmtType, nCurFmtIndex, aAdr);
         nFuncFmtType = nCurFmtType;
         nFuncFmtIndex = nCurFmtIndex;
         // If not a result matrix, obtain the cell value.
diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
index ea19289230a2..0f513c231327 100644
--- a/sc/source/core/tool/interpr6.cxx
+++ b/sc/source/core/tool/interpr6.cxx
@@ -319,13 +319,14 @@ public:
 
 class FuncCount : public sc::ColumnSpanSet::ColumnAction
 {
+    const ScInterpreterContext& mrContext;
     sc::ColumnBlockConstPosition maPos;
     ScColumn* mpCol;
     size_t mnCount;
     sal_uInt32 mnNumFmt;
 
 public:
-    FuncCount() : mpCol(nullptr), mnCount(0), mnNumFmt(0) {}
+    FuncCount(const ScInterpreterContext& rContext) : mrContext(rContext), mpCol(nullptr), mnCount(0), mnNumFmt(0) {}
 
     virtual void startColumn(ScColumn* pCol) override
     {
@@ -341,7 +342,7 @@ public:
         NumericCellCounter aFunc;
         maPos.miCellPos = sc::ParseBlock(maPos.miCellPos, mpCol->GetCellStore(), aFunc, nRow1, nRow2);
         mnCount += aFunc.getCount();
-        mnNumFmt = mpCol->GetNumberFormat(nRow2);
+        mnNumFmt = mpCol->GetNumberFormat(mrContext, nRow2);
     };
 
     size_t getCount() const { return mnCount; }
@@ -350,6 +351,7 @@ public:
 
 class FuncSum : public sc::ColumnSpanSet::ColumnAction
 {
+    const ScInterpreterContext& mrContext;
     sc::ColumnBlockConstPosition maPos;
     ScColumn* mpCol;
     double mfSum;
@@ -357,7 +359,7 @@ class FuncSum : public sc::ColumnSpanSet::ColumnAction
     sal_uInt32 mnNumFmt;
 
 public:
-    FuncSum() : mpCol(nullptr), mfSum(0.0), mnError(FormulaError::NONE), mnNumFmt(0) {}
+    FuncSum(const ScInterpreterContext& rContext) : mrContext(rContext), mpCol(nullptr), mfSum(0.0), mnError(FormulaError::NONE), mnNumFmt(0) {}
 
     virtual void startColumn(ScColumn* pCol) override
     {
@@ -389,7 +391,7 @@ public:
             mfSum += aFunc.getRest();
         }
 
-        mnNumFmt = mpCol->GetNumberFormat(nRow2);
+        mnNumFmt = mpCol->GetNumberFormat(mrContext, nRow2);
     };
 
     FormulaError getError() const { return mnError; }
@@ -821,7 +823,7 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
 
                     if ( eFunc == ifSUM )
                     {
-                        FuncSum aAction;
+                        FuncSum aAction(mrContext);
                         aSet.executeColumnAction( *pDok, aAction, fMem );
                         FormulaError nErr = aAction.getError();
                         if ( nErr != FormulaError::NONE )
@@ -836,7 +838,7 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                     }
                     else
                     {
-                        FuncCount aAction;
+                        FuncCount aAction(mrContext);
                         aSet.executeColumnAction(*pDok, aAction);
                         nCount += aAction.getCount();
 
@@ -853,7 +855,7 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                     if (aValIter.GetFirst(fVal, nErr))
                     {
                         // placed the loop on the inside for performance reasons:
-                        aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
+                        aValIter.GetCurNumFmtInfo( mrContext, nFuncFmtType, nFuncFmtIndex );
                         switch( eFunc )
                         {
                             case ifAVERAGE:
diff --git a/sc/source/filter/excel/xepivot.cxx b/sc/source/filter/excel/xepivot.cxx
index 999600c58cc3..21f2963f8abb 100644
--- a/sc/source/filter/excel/xepivot.cxx
+++ b/sc/source/filter/excel/xepivot.cxx
@@ -341,7 +341,7 @@ void XclExpPCField::InitStandardField( const ScRange& rRange )
         if( rDoc.HasValueData( aPos.Col(), aPos.Row(), aPos.Tab() ) )
         {
             double fValue = rDoc.GetValue( aPos );
-            short nFmtType = rFormatter.GetType( rDoc.GetNumberFormat( aPos ) );
+            short nFmtType = rFormatter.GetType( rDoc.GetNumberFormat( rDoc.GetNonThreadedContext(), aPos ) );
             if( nFmtType == css::util::NumberFormat::LOGICAL )
                 InsertOrigBoolItem( fValue != 0, aText );
             else if( nFmtType & css::util::NumberFormat::DATETIME )
diff --git a/sc/source/filter/excel/xicontent.cxx b/sc/source/filter/excel/xicontent.cxx
index cf4163c82cff..8cdbde3bb22d 100644
--- a/sc/source/filter/excel/xicontent.cxx
+++ b/sc/source/filter/excel/xicontent.cxx
@@ -173,7 +173,7 @@ void lclInsertUrl( XclImpRoot& rRoot, const OUString& rUrl, SCCOL nScCol, SCROW
         case CELLTYPE_STRING:
         case CELLTYPE_EDIT:
         {
-            sal_uLong nNumFmt = rDoc.getDoc().GetNumberFormat(aScPos);
+            sal_uLong nNumFmt = rDoc.getDoc().GetNumberFormat(rDoc.getDoc().GetNonThreadedContext(), aScPos);
             SvNumberFormatter* pFormatter = rDoc.getDoc().GetFormatTable();
             Color* pColor;
             OUString aDisplText;
diff --git a/sc/source/ui/docshell/externalrefmgr.cxx b/sc/source/ui/docshell/externalrefmgr.cxx
index beb47fc010dd..c7c380178e74 100644
--- a/sc/source/ui/docshell/externalrefmgr.cxx
+++ b/sc/source/ui/docshell/externalrefmgr.cxx
@@ -2878,7 +2878,7 @@ public:
             if (pTok)
             {
                 // Cache this cell.
-                mpRefTab->setCell(mpCurCol->GetCol(), nRow, pTok, mpCurCol->GetNumberFormat(nRow));
+                mpRefTab->setCell(mpCurCol->GetCol(), nRow, pTok, mpCurCol->GetNumberFormat(mpCurCol->GetDoc().GetNonThreadedContext(), nRow));
                 mpRefTab->setCachedCell(mpCurCol->GetCol(), nRow);
             }
         }
commit 3695439ada8f9a85a2ef405d07875e4b73f09c6c
Author: Tor Lillqvist <tml at collabora.com>
Date:   Fri Sep 29 17:43:24 2017 +0300

    Disable formula group threading for macros and table ops
    
    Those are likely highly problematic to do in parallel.
    
    Change-Id: I50cc32eb72f6b7951d247ecd787b2942cd7d9163

diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index d6ee44cf86c0..d0ebe0ca2e76 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -1337,16 +1337,28 @@ bool ScTokenArray::AddFormulaToken(
 
 void ScTokenArray::CheckToken( const FormulaToken& r )
 {
+    static const std::set<OpCode> aThreadedCalcBlackList({
+        ocMacro,
+        ocTableOp
+    });
+
     if (IsFormulaVectorDisabled())
         // It's already disabled.  No more checking needed.
         return;
 
     static const bool bThreadingRequested = std::getenv("CPU_THREADED_CALCULATION");
 
+    OpCode eOp = r.GetOpCode();
+
     if (!ScCalcConfig::isOpenCLEnabled() && bThreadingRequested)
+    {
+        if (aThreadedCalcBlackList.count(eOp))
+        {
+            meVectorState = FormulaVectorDisabledNotInSubSet;
+            SAL_INFO("sc.core.formulagroup", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp) << " disables threaded calculation of formula group");
+        }
         return;
-
-    OpCode eOp = r.GetOpCode();
+    }
 
     if (SC_OPCODE_START_FUNCTION <= eOp && eOp < SC_OPCODE_STOP_FUNCTION)
     {
commit 07c7ab11ead9345998b10d5613648953ad09c9e5
Author: Tor Lillqvist <tml at collabora.com>
Date:   Fri Sep 29 17:01:03 2017 +0300

    Move nInterpreterTableOpLevel back to ScDocument
    
    Change-Id: I4de0051d9fa5de9147954c6021d47076145a3e59

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index d8d0879f6a87..e85b4ba29365 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -276,14 +276,11 @@ const sal_uInt8 SC_DDE_IGNOREMODE    = 255;       /// For usage in FindDdeLink()
 // During threaded calculation fields being mutated are kept in this struct
 struct ScDocumentThreadSpecific
 {
-    sal_uInt16              nInterpreterTableOpLevel;       // >0 if in interpreter TableOp
-
     ScRecursionHelper*      pRecursionHelper;               // information for recursive and iterative cell formulas
 
     ScLookupCacheMapImpl*   pLookupCacheMapImpl;            // cache for lookups like VLOOKUP and MATCH
 
     ScDocumentThreadSpecific() :
-        nInterpreterTableOpLevel(0),
         pRecursionHelper(nullptr),
         pLookupCacheMapImpl(nullptr)
     {
@@ -456,6 +453,7 @@ private:
     sal_uLong               nXMLImportedFormulaCount;        // progress count during XML import
     sal_uInt16              nInterpretLevel;                // >0 if in interpreter
     sal_uInt16              nMacroInterpretLevel;           // >0 if macro in interpreter
+    sal_uInt16              nInterpreterTableOpLevel;       // >0 if in interpreter TableOp
 
     ScDocumentThreadSpecific maNonThreaded;
 
@@ -2193,9 +2191,17 @@ public:
                                 if ( nMacroInterpretLevel )
                                     nMacroInterpretLevel--;
                             }
-    bool                IsInInterpreterTableOp() const;
-    void                IncInterpreterTableOpLevel();
-    void                DecInterpreterTableOpLevel();
+    bool                IsInInterpreterTableOp() const { return nInterpreterTableOpLevel != 0; }
+    void                IncInterpreterTableOpLevel()
+                            {
+                                if ( nInterpreterTableOpLevel < USHRT_MAX )
+                                    nInterpreterTableOpLevel++;
+                            }
+    void                DecInterpreterTableOpLevel()
+                            {
+                                if ( nInterpreterTableOpLevel )
+                                    nInterpreterTableOpLevel--;
+                            }
 
     // add a formula to be remembered for TableOp broadcasts
     void                AddTableOpFormulaCell( ScFormulaCell* );
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 9fab88f4e910..283c082199b2 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -176,6 +176,7 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
         nXMLImportedFormulaCount( 0 ),
         nInterpretLevel(0),
         nMacroInterpretLevel(0),
+        nInterpreterTableOpLevel(0),
         nSrcVer( SC_CURRENT_VERSION ),
         nFormulaTrackCount(0),
         eHardRecalcState(HardRecalcState::OFF),
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 1706342ccd36..185115ac8ad7 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -6771,42 +6771,6 @@ ScMutationGuard::~ScMutationGuard()
 
 thread_local ScDocumentThreadSpecific ScDocument::maThreadSpecific;
 
-bool ScDocument::IsInInterpreterTableOp() const
-{
-    if (!mbThreadedGroupCalcInProgress)
-        return maNonThreaded.nInterpreterTableOpLevel != 0;
-    else
-        return maThreadSpecific.nInterpreterTableOpLevel != 0;
-}
-
-void ScDocument::IncInterpreterTableOpLevel()
-{
-    if (!mbThreadedGroupCalcInProgress)
-    {
-        if (maNonThreaded.nInterpreterTableOpLevel < USHRT_MAX)
-            maNonThreaded.nInterpreterTableOpLevel++;
-    }
-    else
-    {
-        if (maThreadSpecific.nInterpreterTableOpLevel < USHRT_MAX)
-            maThreadSpecific.nInterpreterTableOpLevel++;
-    }
-}
-
-void ScDocument::DecInterpreterTableOpLevel()
-{
-    if (!mbThreadedGroupCalcInProgress)
-    {
-        if (maNonThreaded.nInterpreterTableOpLevel)
-            maNonThreaded.nInterpreterTableOpLevel--;
-    }
-    else
-    {
-        if (maThreadSpecific.nInterpreterTableOpLevel)
-            maThreadSpecific.nInterpreterTableOpLevel--;
-    }
-}
-
 ScRecursionHelper& ScDocument::GetRecursionHelper()
 {
     if (!mbThreadedGroupCalcInProgress)
@@ -6825,16 +6789,12 @@ ScRecursionHelper& ScDocument::GetRecursionHelper()
 
 void ScDocumentThreadSpecific::SetupFromNonThreadedData(const ScDocumentThreadSpecific& rNonThreadedData)
 {
-    nInterpreterTableOpLevel = rNonThreadedData.nInterpreterTableOpLevel;
-
     // What about the recursion helper?
     // Copy the lookup cache?
 }
 
 void ScDocumentThreadSpecific::MergeBackIntoNonThreadedData(ScDocumentThreadSpecific& rNonThreadedData)
 {
-    assert(nInterpreterTableOpLevel == rNonThreadedData.nInterpreterTableOpLevel);
-
     // What about recursion helper and lookup cache?
 }
 
commit e40902d30f596d3fd804728240288a92ccc66e5d
Author: Tor Lillqvist <tml at collabora.com>
Date:   Fri Sep 29 16:00:18 2017 +0300

    Move nMacroInterpretLevel back to ScDocument
    
    Change-Id: I48748434c845af963af160f8bbd75e4ab7ce95bd

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index d253a17c60ef..d8d0879f6a87 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -276,7 +276,6 @@ const sal_uInt8 SC_DDE_IGNOREMODE    = 255;       /// For usage in FindDdeLink()
 // During threaded calculation fields being mutated are kept in this struct
 struct ScDocumentThreadSpecific
 {
-    sal_uInt16              nMacroInterpretLevel;           // >0 if macro in interpreter
     sal_uInt16              nInterpreterTableOpLevel;       // >0 if in interpreter TableOp
 
     ScRecursionHelper*      pRecursionHelper;               // information for recursive and iterative cell formulas
@@ -284,7 +283,6 @@ struct ScDocumentThreadSpecific
     ScLookupCacheMapImpl*   pLookupCacheMapImpl;            // cache for lookups like VLOOKUP and MATCH
 
     ScDocumentThreadSpecific() :
-        nMacroInterpretLevel(0),
         nInterpreterTableOpLevel(0),
         pRecursionHelper(nullptr),
         pLookupCacheMapImpl(nullptr)
@@ -457,6 +455,7 @@ private:
     sal_uLong               nFormulaCodeInTree;             // formula RPN in the formula tree
     sal_uLong               nXMLImportedFormulaCount;        // progress count during XML import
     sal_uInt16              nInterpretLevel;                // >0 if in interpreter
+    sal_uInt16              nMacroInterpretLevel;           // >0 if macro in interpreter
 
     ScDocumentThreadSpecific maNonThreaded;
 
@@ -2181,9 +2180,19 @@ public:
                                 if ( nInterpretLevel )
                                     nInterpretLevel--;
                             }
-    sal_uInt16          GetMacroInterpretLevel();
-    void                IncMacroInterpretLevel();
-    void                DecMacroInterpretLevel();
+    sal_uInt16          GetMacroInterpretLevel() { return nMacroInterpretLevel; }
+    void                IncMacroInterpretLevel()
+                            {
+                                assert(!mbThreadedGroupCalcInProgress);
+                                if ( nMacroInterpretLevel < USHRT_MAX )
+                                    nMacroInterpretLevel++;
+                            }
+    void                DecMacroInterpretLevel()
+                            {
+                                assert(!mbThreadedGroupCalcInProgress);
+                                if ( nMacroInterpretLevel )
+                                    nMacroInterpretLevel--;
+                            }
     bool                IsInInterpreterTableOp() const;
     void                IncInterpreterTableOpLevel();
     void                DecInterpreterTableOpLevel();
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index c5d0c7e8cea2..9fab88f4e910 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -175,6 +175,7 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
         nFormulaCodeInTree(0),
         nXMLImportedFormulaCount( 0 ),
         nInterpretLevel(0),
+        nMacroInterpretLevel(0),
         nSrcVer( SC_CURRENT_VERSION ),
         nFormulaTrackCount(0),
         eHardRecalcState(HardRecalcState::OFF),
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 2df3f8e10a8b..1706342ccd36 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -6771,30 +6771,6 @@ ScMutationGuard::~ScMutationGuard()
 
 thread_local ScDocumentThreadSpecific ScDocument::maThreadSpecific;
 
-sal_uInt16 ScDocument::GetMacroInterpretLevel()
-{
-    if (!mbThreadedGroupCalcInProgress)
-        return maNonThreaded.nMacroInterpretLevel;
-    else
-        return maThreadSpecific.nMacroInterpretLevel;
-}
-
-void ScDocument::IncMacroInterpretLevel()
-{
-    if (!mbThreadedGroupCalcInProgress)
-        maNonThreaded.nMacroInterpretLevel++;
-    else
-        maThreadSpecific.nMacroInterpretLevel++;
-}
-
-void ScDocument::DecMacroInterpretLevel()
-{
-    if (!mbThreadedGroupCalcInProgress)
-        maNonThreaded.nMacroInterpretLevel--;
-    else
-        maThreadSpecific.nMacroInterpretLevel--;
-}
-
 bool ScDocument::IsInInterpreterTableOp() const
 {
     if (!mbThreadedGroupCalcInProgress)
@@ -6849,7 +6825,6 @@ ScRecursionHelper& ScDocument::GetRecursionHelper()
 
 void ScDocumentThreadSpecific::SetupFromNonThreadedData(const ScDocumentThreadSpecific& rNonThreadedData)
 {
-    nMacroInterpretLevel = rNonThreadedData.nMacroInterpretLevel;
     nInterpreterTableOpLevel = rNonThreadedData.nInterpreterTableOpLevel;
 
     // What about the recursion helper?
@@ -6858,7 +6833,6 @@ void ScDocumentThreadSpecific::SetupFromNonThreadedData(const ScDocumentThreadSp
 
 void ScDocumentThreadSpecific::MergeBackIntoNonThreadedData(ScDocumentThreadSpecific& rNonThreadedData)
 {
-    assert(nMacroInterpretLevel == rNonThreadedData.nMacroInterpretLevel);
     assert(nInterpreterTableOpLevel == rNonThreadedData.nInterpreterTableOpLevel);
 
     // What about recursion helper and lookup cache?
commit 6f78078499a7c9f091fa828bcc8970686880e3cf
Author: Tor Lillqvist <tml at collabora.com>
Date:   Fri Sep 29 14:26:29 2017 +0300

    Move nInterpretLevel back to ScDocument
    
    Move the calls to increment and decrement it out of InterpretTail(),
    to those call sites that aren't reached during parallelized
    calculations.
    
    Change-Id: Ie1bd03dd62aea5f6c71c383df21afff29391dade

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index c5ab947feb95..d253a17c60ef 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -276,7 +276,6 @@ const sal_uInt8 SC_DDE_IGNOREMODE    = 255;       /// For usage in FindDdeLink()
 // During threaded calculation fields being mutated are kept in this struct
 struct ScDocumentThreadSpecific
 {
-    sal_uInt16              nInterpretLevel;                // >0 if in interpreter
     sal_uInt16              nMacroInterpretLevel;           // >0 if macro in interpreter
     sal_uInt16              nInterpreterTableOpLevel;       // >0 if in interpreter TableOp
 
@@ -285,7 +284,6 @@ struct ScDocumentThreadSpecific
     ScLookupCacheMapImpl*   pLookupCacheMapImpl;            // cache for lookups like VLOOKUP and MATCH
 
     ScDocumentThreadSpecific() :
-        nInterpretLevel(0),
         nMacroInterpretLevel(0),
         nInterpreterTableOpLevel(0),
         pRecursionHelper(nullptr),
@@ -458,6 +456,8 @@ private:
 
     sal_uLong               nFormulaCodeInTree;             // formula RPN in the formula tree
     sal_uLong               nXMLImportedFormulaCount;        // progress count during XML import
+    sal_uInt16              nInterpretLevel;                // >0 if in interpreter
+
     ScDocumentThreadSpecific maNonThreaded;
 
     // There can be only one ScDocument being calculated in a thread at a time, so we can use a
@@ -2167,9 +2167,20 @@ public:
     void                SetForcedFormulas( bool bVal ) { bHasForcedFormulas = bVal; }
     sal_uLong           GetFormulaCodeInTree() const { return nFormulaCodeInTree; }
 
-    bool                IsInInterpreter() const;
-    void                IncInterpretLevel();
-    void                DecInterpretLevel();
+    bool                IsInInterpreter() const { return nInterpretLevel != 0; }
+
+    void                IncInterpretLevel()
+                            {
+                                assert(!mbThreadedGroupCalcInProgress);
+                                if ( nInterpretLevel < USHRT_MAX )
+                                    nInterpretLevel++;
+                            }
+    void                DecInterpretLevel()
+                            {
+                                assert(!mbThreadedGroupCalcInProgress);
+                                if ( nInterpretLevel )
+                                    nInterpretLevel--;
+                            }
     sal_uInt16          GetMacroInterpretLevel();
     void                IncMacroInterpretLevel();
     void                DecMacroInterpretLevel();
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 701305d708f4..705b5ed83ae5 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1,4 +1,4 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
 /*
  * This file is part of the LibreOffice project.
  *
@@ -2899,6 +2899,9 @@ void ScColumn::CalculateInThread( SCROW nRow, size_t nLen, unsigned nThisThread,
             continue;
 
         ScFormulaCell& rCell = **itCell;
+        // Here we don't call IncInterpretLevel() and DecInterpretLevel() as this call site is
+        // always in a threaded calculation.
+        assert(pDocument->mbThreadedGroupCalcInProgress);
         rCell.InterpretTail(ScFormulaCell::SCITP_NORMAL);
     }
 }
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 43332c2ec873..c5d0c7e8cea2 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -174,6 +174,7 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
         mbThreadedGroupCalcInProgress( false ),
         nFormulaCodeInTree(0),
         nXMLImportedFormulaCount( 0 ),
+        nInterpretLevel(0),
         nSrcVer( SC_CURRENT_VERSION ),
         nFormulaTrackCount(0),
         eHardRecalcState(HardRecalcState::OFF),
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 2f2a0dabe995..2df3f8e10a8b 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -6771,30 +6771,6 @@ ScMutationGuard::~ScMutationGuard()
 
 thread_local ScDocumentThreadSpecific ScDocument::maThreadSpecific;
 
-bool ScDocument::IsInInterpreter() const
-{
-    if (!mbThreadedGroupCalcInProgress)
-        return maNonThreaded.nInterpretLevel != 0;
-    else
-        return maThreadSpecific.nInterpretLevel != 0;
-}
-
-void ScDocument::IncInterpretLevel()
-{
-    if (!mbThreadedGroupCalcInProgress)
-        maNonThreaded.nInterpretLevel++;
-    else
-        maThreadSpecific.nInterpretLevel++;
-}
-
-void ScDocument::DecInterpretLevel()
-{
-    if (!mbThreadedGroupCalcInProgress)
-        maNonThreaded.nInterpretLevel--;
-    else
-        maThreadSpecific.nInterpretLevel--;
-}
-
 sal_uInt16 ScDocument::GetMacroInterpretLevel()
 {
     if (!mbThreadedGroupCalcInProgress)
@@ -6873,7 +6849,6 @@ ScRecursionHelper& ScDocument::GetRecursionHelper()
 
 void ScDocumentThreadSpecific::SetupFromNonThreadedData(const ScDocumentThreadSpecific& rNonThreadedData)
 {
-    nInterpretLevel = rNonThreadedData.nInterpretLevel;
     nMacroInterpretLevel = rNonThreadedData.nMacroInterpretLevel;
     nInterpreterTableOpLevel = rNonThreadedData.nInterpreterTableOpLevel;
 
@@ -6883,7 +6858,6 @@ void ScDocumentThreadSpecific::SetupFromNonThreadedData(const ScDocumentThreadSp
 
 void ScDocumentThreadSpecific::MergeBackIntoNonThreadedData(ScDocumentThreadSpecific& rNonThreadedData)
 {
-    assert(nInterpretLevel == rNonThreadedData.nInterpretLevel);
     assert(nMacroInterpretLevel == rNonThreadedData.nMacroInterpretLevel);
     assert(nInterpreterTableOpLevel == rNonThreadedData.nInterpreterTableOpLevel);
 
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index e0bc6aab9037..bc6fd157e34b 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -1522,6 +1522,7 @@ void ScFormulaCell::Interpret()
     }
     else
     {
+        pDocument->IncInterpretLevel();
 #if DEBUG_CALCULATION
         aDC.enterGroup();
         bool bGroupInterpreted = InterpretFormulaGroup();
@@ -1532,6 +1533,7 @@ void ScFormulaCell::Interpret()
         if (!InterpretFormulaGroup())
             InterpretTail( SCITP_NORMAL);
 #endif
+        pDocument->DecInterpretLevel();
     }
 
     // While leaving a recursion or iteration stack, insert its cells to the
@@ -1592,8 +1594,10 @@ void ScFormulaCell::Interpret()
                 {
                     bResumeIteration = false;
                     // Close circle once.
+                    pDocument->IncInterpretLevel();
                     rRecursionHelper.GetList().back().pCell->InterpretTail(
                             SCITP_CLOSE_ITERATION_CIRCLE);
+                    pDocument->DecInterpretLevel();
                     // Start at 1, init things.
                     rRecursionHelper.StartIteration();
                     // Mark all cells being in iteration.
@@ -1622,7 +1626,9 @@ void ScFormulaCell::Interpret()
                                 pIterCell->GetSeenInIteration())
                         {
                             (*aIter).aPreviousResult = pIterCell->aResult;
+                            pDocument->IncInterpretLevel();
                             pIterCell->InterpretTail( SCITP_FROM_ITERATION);
+                            pDocument->DecInterpretLevel();
                         }
                         rDone = rDone && !pIterCell->IsDirtyOrInTableOpDirty();
                     }
@@ -1692,7 +1698,9 @@ void ScFormulaCell::Interpret()
                         ScFormulaCell* pCell = (*aIter).pCell;
                         if (pCell->IsDirtyOrInTableOpDirty())
                         {
+                            pDocument->IncInterpretLevel();
                             pCell->InterpretTail( SCITP_NORMAL);
+                            pDocument->DecInterpretLevel();
                             if (!pCell->IsDirtyOrInTableOpDirty() && !pCell->IsIterCell())
                                 pCell->bRunning = (*aIter).bOldRunning;
                         }
@@ -1728,16 +1736,14 @@ void ScFormulaCell::Interpret()
 namespace {
 class StackCleaner
 {
-    ScDocument*     pDoc;
     ScInterpreter*  pInt;
     public:
-    StackCleaner( ScDocument* pD, ScInterpreter* pI )
-        : pDoc(pD), pInt(pI)
+    StackCleaner( ScInterpreter* pI )
+        : pInt(pI)
         {}
     ~StackCleaner()
     {
         delete pInt;
-        pDoc->DecInterpretLevel();
     }
 };
 }
@@ -1769,9 +1775,8 @@ void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam )
 
     if( pCode->GetCodeLen() && pDocument )
     {
-        pDocument->IncInterpretLevel();
         ScInterpreter* pInterpreter = new ScInterpreter( this, pDocument, aPos, *pCode );
-        StackCleaner aStackCleaner( pDocument, pInterpreter);
+        StackCleaner aStackCleaner(pInterpreter);
         FormulaError nOldErrCode = aResult.GetResultError();
         if ( nSeenInIteration == 0 )
         {   // Only the first time
@@ -2163,9 +2168,8 @@ void ScFormulaCell::HandleStuffAfterParallelCalculation()
         if ( !pCode->IsRecalcModeAlways() )
             pDocument->RemoveFromFormulaTree( this );
 
-        pDocument->IncInterpretLevel();
         ScInterpreter* pInterpreter = new ScInterpreter( this, pDocument, aPos, *pCode );
-        StackCleaner aStackCleaner( pDocument, pInterpreter);
+        StackCleaner aStackCleaner(pInterpreter);
 
         switch (pInterpreter->GetVolatileType())
         {
commit 0a2e85e7f2852cadad0a1fab7e13323d06478b00
Author: Tor Lillqvist <tml at collabora.com>
Date:   Fri Sep 29 11:04:17 2017 +0300

    Re-work how the thread-specific data in ScDocument works
    
    We can use normal thread_local data for it as a thread can only be
    acting on one ScDocument in parallelized formula group calculation
    anyway. Use separate data instance for the non-threaded data, and when
    a thread starts, copy that to the thread-specific data.
    
    Change-Id: I3e58320a728d1c5639a8a078748b3d4d7a451b25

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 64929d7e43ac..c5ab947feb95 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1,4 +1,4 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
 /*
  * This file is part of the LibreOffice project.
  *
@@ -273,6 +273,7 @@ const sal_uInt8 SC_DDE_ENGLISH       = 1;
 const sal_uInt8 SC_DDE_TEXT          = 2;
 const sal_uInt8 SC_DDE_IGNOREMODE    = 255;       /// For usage in FindDdeLink() only!
 
+// During threaded calculation fields being mutated are kept in this struct
 struct ScDocumentThreadSpecific
 {
     sal_uInt16              nInterpretLevel;                // >0 if in interpreter
@@ -295,6 +296,12 @@ struct ScDocumentThreadSpecific
     ~ScDocumentThreadSpecific()
     {
     }
+
+    // To be called in the thread at start
+    void SetupFromNonThreadedData(const ScDocumentThreadSpecific& rNonThreadedData);
+
+    // To be called in the main thread after the thread has finished
+    void MergeBackIntoNonThreadedData(ScDocumentThreadSpecific& rNonThreadedData);
 };
 
 enum class ScMutationGuardFlags
@@ -437,6 +444,7 @@ public:
     /// list of ScInterpreterTableOpParams currently in use
     std::vector<std::unique_ptr<ScInterpreterTableOpParams>> m_TableOpList;
     ScInterpreterTableOpParams  aLastTableOpParams;     // remember last params
+
 private:
 
     LanguageType        eLanguage;                      // default language
@@ -450,7 +458,12 @@ private:
 
     sal_uLong               nFormulaCodeInTree;             // formula RPN in the formula tree
     sal_uLong               nXMLImportedFormulaCount;        // progress count during XML import
-    static thread_local std::map<const ScDocument *, ScDocumentThreadSpecific> maThreadSpecific;
+    ScDocumentThreadSpecific maNonThreaded;
+
+    // There can be only one ScDocument being calculated in a thread at a time, so we can use a
+    // plain thread_local static member.
+    thread_local static ScDocumentThreadSpecific maThreadSpecific;
+
     sal_uInt16              nSrcVer;                        // file version (load/save)
     sal_uInt16              nFormulaTrackCount;
     HardRecalcState         eHardRecalcState;               // off, temporary, eternal
@@ -2046,7 +2059,7 @@ public:
     void SC_DLLPUBLIC SetFormulaResults( const ScAddress& rTopPos, const double* pResults, size_t nLen );
     void SC_DLLPUBLIC SetFormulaResults( const ScAddress& rTopPos, const formula::FormulaConstTokenRef* pResults, size_t nLen );
 
-    void CalculateInColumnInThread( const ScAddress& rTopPos, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal);
+    ScDocumentThreadSpecific CalculateInColumnInThread( const ScAddress& rTopPos, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal);
     void HandleStuffAfterParallelCalculation( const ScAddress& rTopPos, size_t nLen );
 
     /**
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 3c3266225c1b..43332c2ec873 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -396,10 +396,8 @@ ScDocument::~ScDocument()
     ScAddInListener::RemoveDocument( this );
     DELETEZ( pChartListenerCollection);   // before pBASM because of potential Listener!
 
-    if (maThreadSpecific.find(this) != maThreadSpecific.end())
-    {
-        DELETEZ( maThreadSpecific[this].pLookupCacheMapImpl ); // before pBASM because of listeners
-    }
+    DELETEZ(maNonThreaded.pLookupCacheMapImpl);  // before pBASM because of listeners
+    DELETEZ(maThreadSpecific.pLookupCacheMapImpl);
 
     // destroy BroadcastAreas first to avoid un-needed Single-EndListenings of Formula-Cells
     delete pBASM;       // BroadcastAreaSlotMachine
@@ -449,16 +447,14 @@ ScDocument::~ScDocument()
     mxPoolHelper.clear();
 
     delete pScriptTypeData;
-    if (maThreadSpecific.find(this) != maThreadSpecific.end())
-        delete maThreadSpecific[this].pRecursionHelper;
+    delete maNonThreaded.pRecursionHelper;
+    delete maThreadSpecific.pRecursionHelper;
 
     delete pPreviewFont;
     SAL_WARN_IF( pAutoNameCache, "sc.core", "AutoNameCache still set in dtor" );
 
     mpFormulaGroupCxt.reset();
     mpCellStringPool.reset();
-
-    maThreadSpecific.erase(this);
 }
 
 void ScDocument::InitClipPtrs( ScDocument* pSourceDoc )
@@ -1234,50 +1230,103 @@ ScRecursionHelper* ScDocument::CreateRecursionHelperInstance()
 ScLookupCache & ScDocument::GetLookupCache( const ScRange & rRange )
 {
     ScLookupCache* pCache = nullptr;
-    if (!maThreadSpecific[this].pLookupCacheMapImpl)
-        maThreadSpecific[this].pLookupCacheMapImpl = new ScLookupCacheMapImpl;

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list