Index: runtime/vm/verified_memory.h |
=================================================================== |
--- runtime/vm/verified_memory.h (revision 0) |
+++ runtime/vm/verified_memory.h (revision 0) |
@@ -0,0 +1,88 @@ |
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+#ifndef VM_VERIFIED_MEMORY_H_ |
+#define VM_VERIFIED_MEMORY_H_ |
+ |
+#include "vm/allocation.h" |
+#include "vm/flags.h" |
+#include "vm/virtual_memory.h" |
+ |
+namespace dart { |
+ |
+#if defined(DEBUG) |
+DECLARE_FLAG(bool, verified_mem); |
+DECLARE_FLAG(int, verified_mem_max_reserve_mb); |
+#endif |
+ |
+ |
+// A wrapper around VirtualMemory for verifying that a particular class of |
+// memory writes are only performed through a particular interface. |
+// |
+// The main use case is verifying that storing pointers into objects is only |
+// performed by code aware of the GC write barrier. |
+// |
+// NOTE: Verification is enabled only if 'verified_mem' is true, and this flag |
+// only exists in DEBUG builds. |
+class VerifiedMemory : public AllStatic { |
+ public: |
+ // Reserves a block of memory for which all methods in this class may |
+ // be called. Returns NULL if out of memory. |
+ static VirtualMemory* Reserve(intptr_t size) { |
+ return enabled() ? ReserveInternal(size) : VirtualMemory::Reserve(size); |
+ } |
+ |
+ // Verifies that [start, start + size) has only been mutated through |
+ // methods in this class (or explicitly accepted by calling Accept). |
+ static void Verify(uword start, intptr_t size) { |
+ if (!enabled()) return; |
+ ASSERT(size <= offset()); |
+ ASSERT(memcmp(reinterpret_cast<void*>(start + offset()), |
+ reinterpret_cast<void*>(start), |
+ size) == 0); |
+ } |
+ |
+ // Assigns value to *ptr after verifying previous content at that location. |
+ template<typename T> |
+ static void Write(T* ptr, const T& value) { |
+ if (enabled()) { |
+ uword addr = reinterpret_cast<uword>(ptr); |
+ Verify(addr, sizeof(T)); |
+ T* offset_ptr = reinterpret_cast<T*>(addr + offset()); |
+ *offset_ptr = value; |
+ } |
+ *ptr = value; |
+ } |
+ |
+ // Accepts the current state of [start, start + size), even if it has been |
+ // mutated by other means. |
+ static void Accept(uword start, intptr_t size) { |
+ if (!enabled()) return; |
+ ASSERT(size <= offset()); |
+ memmove(reinterpret_cast<void*>(start + offset()), |
+ reinterpret_cast<void*>(start), |
+ size); |
+ } |
+ |
+ private: |
+#if defined(DEBUG) |
+ static bool enabled() { return FLAG_verified_mem; } |
+ static intptr_t offset() { return FLAG_verified_mem_max_reserve_mb * MB; } |
+ static VirtualMemory* ReserveInternal(intptr_t size); |
+#else |
+ // In release mode, most code in this class is optimized away. |
+ static bool enabled() { return false; } |
+ static intptr_t offset() { UNREACHABLE(); return -1; } |
+ static VirtualMemory* ReserveInternal(intptr_t size) { |
+ UNREACHABLE(); |
+ return NULL; |
+ } |
+#endif |
+ |
+ friend class Assembler; // To use enabled/offset when generating code. |
+}; |
+ |
+} // namespace dart |
+ |
+#endif // VM_VERIFIED_MEMORY_H_ |