mirror of
https://github.com/dart-lang/sdk
synced 2024-09-23 01:23:47 +00:00
8479136580
With --verified_mem, use VerifiedMemory to duplicate all pointer writes in the heap, and verify that no unaccounted writes occurred. R=iposva@google.com Review URL: https://codereview.chromium.org//711833002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@41700 260f80e4-7a28-3924-810f-c04153c831b5
91 lines
3 KiB
C++
91 lines
3 KiB
C++
// 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_
|