This change adds a setting `target.process.track-memory-cache-changes`. Disabling this setting prevents invalidating and updating values in `ValueObject::UpdateValueIfNeeded` when only "internal" debugger memory is updated. Writing to "internal" debugger memory happens when, for instance, expressions are evaluated by visualizers (pretty printers). One of the examples when cache invalidation has a particularly heavy impact is visualizations of some collections: in some collections getting collection size is an expensive operation (it requires traversal of the collection). At the same time evaluating user expression with side effects (visible to target, not only to debugger) will still bump memory ID because: - If expression is evaluated via interpreter: it will cause write to "non-internal" memory - If expression is JIT-compiled: then to call the function LLDB will write to "non-internal" stack memory The downside of disabled `target.process.track-memory-cache-changes` setting is that convenience variables won't reevaluate synthetic children automatically. --------- Co-authored-by: Mikhail Zakharov <mikhail.zakharov@jetbrains.com>
68 lines
1.7 KiB
C++
68 lines
1.7 KiB
C++
// Tests that ProcessModID.m_memory_id is not bumped when evaluating expressions without side effects.
|
|
|
|
// REQUIRES: target-windows
|
|
// Due to different implementations exact numbers (m_stop_id) are different on different OSs. So we lock this test to specific platform.
|
|
|
|
// RUN: %build %s -o %t
|
|
// RUN: %lldb %t \
|
|
// RUN: -o "settings set target.process.track-memory-cache-changes false" \
|
|
// RUN: -o "run" \
|
|
// RUN: -o "process status -d" \
|
|
// RUN: -o "expr x.i != 42" \
|
|
// RUN: -o "process status -d" \
|
|
// RUN: -o "expr x.get()" \
|
|
// RUN: -o "process status -d" \
|
|
// RUN: -o "expr x.i = 10" \
|
|
// RUN: -o "process status -d" \
|
|
// RUN: -o "continue" \
|
|
// RUN: -o "process status -d" \
|
|
// RUN: -o "exit" | FileCheck %s -dump-input=fail
|
|
|
|
class X {
|
|
int i = 0;
|
|
|
|
public:
|
|
int get() { return i; }
|
|
};
|
|
|
|
int main() {
|
|
X x;
|
|
x.get();
|
|
|
|
__builtin_debugtrap();
|
|
__builtin_debugtrap();
|
|
return 0;
|
|
}
|
|
|
|
// CHECK-LABEL: process status -d
|
|
// CHECK: m_stop_id: 2
|
|
// CHECK: m_memory_id: 0
|
|
|
|
// CHECK-LABEL: expr x.i != 42
|
|
// IDs are not changed when executing simple expressions
|
|
|
|
// CHECK-LABEL: process status -d
|
|
// CHECK: m_stop_id: 2
|
|
// CHECK: m_memory_id: 0
|
|
|
|
// CHECK-LABEL: expr x.get()
|
|
// Expression causes ID to be bumped because LLDB has to execute function
|
|
|
|
// CHECK-LABEL: process status -d
|
|
// CHECK: m_stop_id: 3
|
|
// CHECK: m_memory_id: 1
|
|
|
|
// CHECK-LABEL: expr x.i = 10
|
|
// Expression causes MemoryID to be bumped because LLDB writes to non-cache memory
|
|
|
|
// CHECK-LABEL: process status -d
|
|
// CHECK: m_stop_id: 3
|
|
// CHECK: m_memory_id: 2
|
|
|
|
// CHECK-LABEL: continue
|
|
// Continue causes StopID to be bumped because process is resumed
|
|
|
|
// CHECK-LABEL: process status -d
|
|
// CHECK: m_stop_id: 4
|
|
// CHECK: m_memory_id: 2
|