aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/memory/qv4writebarrier_p.h
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2017-02-08 16:21:02 +0100
committerLars Knoll <lars.knoll@qt.io>2017-03-09 08:59:20 +0000
commit2a554434a571dcefd26cf10ef8c5ae8b3b7d66db (patch)
tree5532f0a0206fbbde0a3099ff1e0ee58188a97275 /src/qml/memory/qv4writebarrier_p.h
parent05de4e044f92dd278a00e410be8f070bc4d66e6f (diff)
Implement a real write barrier
Implement a Steel write barrier for our objects. The barrier is interesting as it can also be used for incremental GC runs by simply turning the barrier on and leaving old objects marked as black. Change-Id: I0b273974d94a990dee3cd9298089b8b202c75bf2 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/memory/qv4writebarrier_p.h')
-rw-r--r--src/qml/memory/qv4writebarrier_p.h100
1 files changed, 88 insertions, 12 deletions
diff --git a/src/qml/memory/qv4writebarrier_p.h b/src/qml/memory/qv4writebarrier_p.h
index c0f508f962..838ed7a456 100644
--- a/src/qml/memory/qv4writebarrier_p.h
+++ b/src/qml/memory/qv4writebarrier_p.h
@@ -55,6 +55,11 @@
QT_BEGIN_NAMESPACE
+#define WRITEBARRIER_steele -1
+#define WRITEBARRIER_none 1
+
+#define WRITEBARRIER(x) (1/WRITEBARRIER_##x == 1)
+
namespace QV4 {
namespace WriteBarrier {
@@ -64,20 +69,79 @@ enum Type {
Barrier
};
-inline void write(QV4::ExecutionEngine *engine, QV4::Heap::Base *base, QV4::Value *slot, QV4::Value value)
+enum NewValueType {
+ Primitive,
+ Object,
+ Unknown
+};
+
+// ### this needs to be filled with a real memory fence once marking is concurrent
+Q_ALWAYS_INLINE void fence() {}
+
+#if WRITEBARRIER(steele)
+
+template <NewValueType type>
+static Q_CONSTEXPR inline bool isRequired() {
+ return type != Primitive;
+}
+
+inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Value value)
+{
+ *slot = value;
+ if (engine->writeBarrierActive && isRequired<Unknown>()) {
+ fence();
+ base->setGrayBit();
+ }
+}
+
+inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Heap::Base *value)
+{
+ *slot = value;
+ if (engine->writeBarrierActive && isRequired<Object>()) {
+ fence();
+ base->setGrayBit();
+ }
+}
+
+inline void write(EngineBase *engine, Heap::Base *base, Heap::Base **slot, Heap::Base *value)
+{
+ *slot = value;
+ if (engine->writeBarrierActive) {
+ fence();
+ base->setGrayBit();
+ }
+}
+
+#elif WRITEBARRIER(none)
+
+template <NewValueType type>
+static Q_CONSTEXPR inline bool isRequired() {
+ return false;
+}
+
+inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Value value)
+{
+ Q_UNUSED(engine);
+ Q_UNUSED(base);
+ *slot = value;
+}
+
+inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Heap::Base *value)
{
Q_UNUSED(engine);
Q_UNUSED(base);
*slot = value;
}
-inline void write(QV4::ExecutionEngine *engine, QV4::Heap::Base *base, QV4::Heap::Base **slot, QV4::Heap::Base *value)
+inline void write(EngineBase *engine, Heap::Base *base, Heap::Base **slot, Heap::Base *value)
{
Q_UNUSED(engine);
Q_UNUSED(base);
*slot = value;
}
+#endif
+
}
namespace Heap {
@@ -88,9 +152,14 @@ struct Pointer {
T operator->() const { return ptr; }
operator T () const { return ptr; }
+ Heap::Base *base() {
+ Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base));
+ Q_ASSERT(base->inUse());
+ return base;
+ }
+
void set(ExecutionEngine *e, T newVal) {
- Q_UNUSED(e);
- ptr = newVal;
+ WriteBarrier::write(e, base(), reinterpret_cast<Heap::Base **>(&ptr), reinterpret_cast<Heap::Base *>(newVal));
}
template <typename Type>
@@ -106,9 +175,14 @@ V4_ASSERT_IS_TRIVIAL(V4PointerCheck)
template <size_t offset>
struct HeapValue : Value {
+ Heap::Base *base() {
+ Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base));
+ Q_ASSERT(base->inUse());
+ return base;
+ }
+
void set(ExecutionEngine *e, const Value &newVal) {
- Q_UNUSED(e);
- setRawValue(newVal.rawValue());
+ WriteBarrier::write(e, base(), this, newVal);
}
};
@@ -118,15 +192,17 @@ struct ValueArray {
uint alloc;
Value values[1];
+ Heap::Base *base() {
+ Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base));
+ Q_ASSERT(base->inUse());
+ return base;
+ }
+
void set(ExecutionEngine *e, uint index, Value v) {
- Q_UNUSED(e);
- Q_ASSERT(index < alloc);
- values[index] = v;
+ WriteBarrier::write(e, base(), values + index, v);
}
void set(ExecutionEngine *e, uint index, Heap::Base *b) {
- Q_UNUSED(e);
- Q_ASSERT(index < alloc);
- values[index] = b;
+ WriteBarrier::write(e, base(), values + index, b);
}
inline const Value &operator[] (uint index) const {
Q_ASSERT(index < alloc);