blob: db292cc4635ed9d37d6bd69e62f26b730dd37e20 [file] [log] [blame]
// 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.
friend class FlowGraphCompiler; // To compute edge counter code size.
friend class Intrinsifier; // To know whether a jump is near or far.
};
} // namespace dart
#endif // VM_VERIFIED_MEMORY_H_