<commit_before>/*
 * Copyright 2014 Milian Wolff <mail@milianw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include <cstdio>
#include <cassert>
#include <cstring>
#include <cstdlib>

#include <atomic>
#include <mutex>
#include <unordered_map>
#include <string>
#include <vector>
#include <algorithm>
#include <tuple>

#include <boost/functional/hash.hpp>

#include <dlfcn.h>
#include <unistd.h>
#include <link.h>

#define UNW_LOCAL_ONLY
#include <libunwind.h>

using namespace std;

using Trace = vector<unw_word_t>;

namespace std {
    template<>
    struct hash<Trace>
    {
        size_t operator() (const Trace& trace) const
        {
            size_t seed = 0;
            for (auto ip : trace) {
                boost::hash_combine(seed, ip);
            }
            boost::hash_combine(seed, trace.size());
            return seed;
        }
    };
}

namespace {

using malloc_t = void* (*) (size_t);
using free_t = void (*) (void*);
using realloc_t = void* (*) (void*, size_t);
using calloc_t = void* (*) (size_t, size_t);
using posix_memalign_t = int (*) (void **, size_t, size_t);
using valloc_t = void* (*) (size_t);
using aligned_alloc_t = void* (*) (size_t, size_t);
using dlopen_t = void* (*) (const char*, int);

malloc_t real_malloc = nullptr;
free_t real_free = nullptr;
realloc_t real_realloc = nullptr;
calloc_t real_calloc = nullptr;
posix_memalign_t real_posix_memalign = nullptr;
valloc_t real_valloc = nullptr;
aligned_alloc_t real_aligned_alloc = nullptr;
dlopen_t real_dlopen = nullptr;

// threadsafe stuff
atomic<bool> moduleCacheDirty(true);

thread_local Trace traceBuffer;

void trace(const int skip = 2)
{
    traceBuffer.clear();

    const size_t MAX_TRACE_SIZE = 64;
    traceBuffer.reserve(MAX_TRACE_SIZE);

    unw_context_t uc;
    unw_getcontext (&uc);

    unw_cursor_t cursor;
    unw_init_local (&cursor, &uc);

    // skip functions we are not interested in
    for (int i = 0; i < skip; ++i) {
        if (unw_step(&cursor) <= 0) {
            return;
        }
    }

    while (unw_step(&cursor) > 0 && traceBuffer.size() < MAX_TRACE_SIZE) {
        unw_word_t ip;
        unw_get_reg(&cursor, UNW_REG_IP, &ip);
        if (!ip) {
            // this seems to happen regularly at the end of every trace and is useless to us
            // not also useless, its also quite slow to continue here into libunwind
            // I'll report this upstream.
            break;
        }
        traceBuffer.push_back(ip);
    }
}

struct HandleGuard
{
    HandleGuard()
        : wasLocked(inHandler)
    {
        inHandler = true;
    }

    ~HandleGuard()
    {
        inHandler = wasLocked;
    }

    const bool wasLocked;
    static thread_local bool inHandler;
};

thread_local bool HandleGuard::inHandler = false;

string env(const char* variable)
{
    const char* value = getenv(variable);
    return value ? string(value) : string();
}

struct Module
{
    string fileName;
    uintptr_t baseAddress;
    uint32_t size;
    unsigned int id;
    bool isExe;

    bool operator<(const Module& module) const
    {
        return make_tuple(baseAddress, size, fileName) < make_tuple(module.baseAddress, module.size, module.fileName);
    }
    bool operator!=(const Module& module) const
    {
        return make_tuple(baseAddress, size, fileName) != make_tuple(module.baseAddress, module.size, module.fileName);
    }
};

struct Data
{
    Data()
    {
        modules.reserve(32);
        ipCache.reserve(65536);
        traceCache.reserve(16384);
        allocationInfo.reserve(16384);

        string outputFileName = env("DUMP_MALLOC_TRACE_OUTPUT") + to_string(getpid());
        out = fopen(outputFileName.c_str(), "wa");
        if (!out) {
            fprintf(stderr, "Failed to open output file: %s\n", outputFileName.c_str());
            exit(1);
        }

        unsetenv("DUMP_MALLOC_TRACE_OUTPUT");
        unsetenv("LD_PRELOAD");
    }

    ~Data()
    {
        HandleGuard::inHandler = true;
        fclose(out);
    }

    void updateModuleCache()
    {
        // check list of loaded modules for unknown ones
        dl_iterate_phdr(dlopen_notify_callback, this);
        moduleCacheDirty = false;
    }

    /**
     * Mostly copied from vogl's src/libbacktrace/btrace.cpp
     */
    static int dlopen_notify_callback(struct dl_phdr_info *info, size_t /*size*/, void *_data)
    {
        auto data = reinterpret_cast<Data*>(_data);
        auto& modules = data->modules;
        bool isExe = false;
        const char *fileName = info->dlpi_name;
        const int BUF_SIZE = 1024;
        char buf[BUF_SIZE];
        // If we don't have a filename and we haven't added our main exe yet, do it now.
        if (!fileName || !fileName[0]) {
            if (modules.empty()) {
                isExe = true;
                ssize_t ret =  readlink("/proc/self/exe", buf, sizeof(buf));
                if ((ret > 0) && (ret < (ssize_t)sizeof(buf))) {
                    buf[ret] = 0;
                    fileName = buf;
                }
            }
            if (!fileName || !fileName[0]) {
                return 0;
            }
        }

        uintptr_t addressStart = 0;
        uintptr_t addressEnd = 0;

        for (int i = 0; i < info->dlpi_phnum; i++) {
            if (info->dlpi_phdr[i].p_type == PT_LOAD) {
                if (addressEnd == 0) {
                    addressStart = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
                    addressEnd = addressStart + info->dlpi_phdr[i].p_memsz;
                } else {
                    uintptr_t addr = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr + info->dlpi_phdr[i].p_memsz;
                    if (addr > addressEnd) {
                        addressEnd = addr;
                    }
                }
            }
        }

        Module module{fileName, addressStart, static_cast<uint32_t>(addressEnd - addressStart), 0, isExe};

        auto it = lower_bound(modules.begin(), modules.end(), module);
        if (it == modules.end() || *it != module) {
            module.id = data->next_module_id++;
            fprintf(data->out, "m %u %s %lx %d\n", module.id, module.fileName.c_str(), module.baseAddress, module.isExe);
            modules.insert(it, module);
        }

        return 0;
    }

    void handleMalloc(void* ptr, size_t size)
    {
        trace();

        lock_guard<mutex> lock(m_mutex);
        if (moduleCacheDirty) {
            updateModuleCache();
        }
        auto it = traceCache.find(traceBuffer);
        if (it == traceCache.end()) {
            // cache before converting
            auto traceId = next_trace_id++;
            it = traceCache.insert(it, {traceBuffer, traceId});
            // ensure ip cache is up2date
            for (auto& ip : traceBuffer) {
                auto ipIt = ipCache.find(ip);
                if (ipIt == ipCache.end()) {
                    // find module and offset from cache
                    auto module = lower_bound(modules.begin(), modules.end(), ip,
                                                [] (const Module& module, const unw_word_t addr) -> bool {
                                                    return module.baseAddress + module.size < addr;
                                                });
                    if (module == modules.end()) {
                        ip = numeric_limits<unsigned int>::max();
                        continue;
                    }
                    auto ipId = next_ipCache_id++;
                    fprintf(out, "i %u %u %lx\n", ipId, module->id, ip - module->baseAddress);
                    ipIt = ipCache.insert(ipIt, {ip, ipId});
                }
                ip = ipIt->second;
            }
            // print trace
            fprintf(out, "t %u ", traceId);
            for (auto ipId : traceBuffer) {
                if (ipId == numeric_limits<unsigned int>::max()) {
                    continue;
                }
                fprintf(out, "%lu ", ipId);
            }
            fputc('\n', out);
        }
        allocationInfo[ptr] = {size, it->second};
        fprintf(out, "+ %lu %u\n", size, it->second);
    }

    void handleFree(void* ptr)
    {
        lock_guard<mutex> lock(m_mutex);
        auto it = allocationInfo.find(ptr);
        if (it == allocationInfo.end()) {
            return;
        }
        fprintf(out, "- %lu %u\n", it->second.size, it->second.traceId);
        allocationInfo.erase(it);
    }

    mutex m_mutex;
    unsigned int next_module_id = 0;
    unsigned int next_thread_id = 0;
    unsigned int next_ipCache_id = 0;
    unsigned int next_trace_id = 0;

    vector<Module> modules;
    unordered_map<unw_word_t, unw_word_t> ipCache;
    unordered_map<vector<unw_word_t>, unsigned int> traceCache;
    struct AllocationInfo
    {
        size_t size;
        unsigned int traceId;
    };
    unordered_map<void*, AllocationInfo> allocationInfo;
    FILE* out = nullptr;
};

unique_ptr<Data> data;

template<typename T>
T findReal(const char* name)
{
    auto ret = dlsym(RTLD_NEXT, name);
    if (!ret) {
        fprintf(stderr, "Could not find original function %s\n", name);
        abort();
    }
    return reinterpret_cast<T>(ret);
}

/**
 * Dummy implementation, since the call to dlsym from findReal triggers a call to calloc.
 *
 * This is only called at startup and will eventually be replaced by the "proper" calloc implementation.
 */
void* dummy_calloc(size_t num, size_t size)
{
    const size_t MAX_SIZE = 1024;
    static char* buf[MAX_SIZE];
    static size_t offset = 0;
    if (!offset) {
        memset(buf, 0, MAX_SIZE);
    }
    size_t oldOffset = offset;
    offset += num * size;
    if (offset >= MAX_SIZE) {
        fprintf(stderr, "failed to initialize, dummy calloc buf size exhausted: %lu requested, %lu available\n", offset, MAX_SIZE);
        abort();
    }
    return buf + oldOffset;
}

void init()
{
    if (data || HandleGuard::inHandler) {
        fprintf(stderr, "initialization recursion detected\n");
        abort();
    }

    HandleGuard guard;

    real_calloc = &dummy_calloc;
    real_calloc = findReal<calloc_t>("calloc");
    real_dlopen = findReal<dlopen_t>("dlopen");
    real_malloc = findReal<malloc_t>("malloc");
    real_free = findReal<free_t>("free");
    real_realloc = findReal<realloc_t>("realloc");
    real_posix_memalign = findReal<posix_memalign_t>("posix_memalign");
    real_valloc = findReal<valloc_t>("valloc");
    real_aligned_alloc = findReal<aligned_alloc_t>("aligned_alloc");

    data.reset(new Data);
}

}

extern "C" {

/// TODO: memalign, pvalloc, ...?

void* malloc(size_t size)
{
    if (!real_malloc) {
        init();
    }

    void* ret = real_malloc(size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(ret, size);
    }

    return ret;
}

void free(void* ptr)
{
    if (!real_free) {
        init();
    }

    real_free(ptr);

    if (ptr && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleFree(ptr);
    }
}

void* realloc(void* ptr, size_t size)
{
    if (!real_realloc) {
        init();
    }

    void* ret = real_realloc(ptr, size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleFree(ptr);
        data->handleMalloc(ret, size);
    }

    return ret;
}

void* calloc(size_t num, size_t size)
{
    if (!real_calloc) {
        init();
    }

    void* ret = real_calloc(num, size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(ret, num*size);
    }

    return ret;
}

int posix_memalign(void **memptr, size_t alignment, size_t size)
{
    if (!real_posix_memalign) {
        init();
    }

    int ret = real_posix_memalign(memptr, alignment, size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(*memptr, size);
    }

    return ret;
}

void* aligned_alloc(size_t alignment, size_t size)
{
    if (!real_aligned_alloc) {
        init();
    }

    void* ret = real_aligned_alloc(alignment, size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(ret, size);
    }

    return ret;
}

void* valloc(size_t size)
{
    if (!real_valloc) {
        init();
    }

    void* ret = real_valloc(size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(ret, size);
    }

    return ret;
}

void *dlopen(const char *filename, int flag)
{
    if (!real_dlopen) {
        init();
    }

    void* ret = real_dlopen(filename, flag);

    if (ret) {
        moduleCacheDirty = true;
    }

    return ret;
}

}
<commit_msg>Use stack-allocated trace buffer.<commit_after>/*
 * Copyright 2014 Milian Wolff <mail@milianw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include <cstdio>
#include <cassert>
#include <cstring>
#include <cstdlib>

#include <atomic>
#include <mutex>
#include <unordered_map>
#include <string>
#include <vector>
#include <algorithm>
#include <tuple>

#include <boost/functional/hash.hpp>

#include <dlfcn.h>
#include <unistd.h>
#include <link.h>

#define UNW_LOCAL_ONLY
#include <libunwind.h>

using namespace std;

const size_t MAX_TRACE_SIZE = 64;

struct Trace
{
    void clear()
    {
        m_size = 0;
    }

    void push_back(unw_word_t ip)
    {
        m_data[m_size++] = ip;
    }

    const unw_word_t* begin() const
    {
        return m_data;
    }
    unw_word_t* begin()
    {
        return m_data;
    }

    const unw_word_t* end() const
    {
        return m_data + m_size;
    }
    unw_word_t* end()
    {
        return m_data + m_size;
    }

    size_t size() const
    {
        return m_size;
    }

    bool operator==(const Trace& o) const
    {
        return m_size == o.m_size && !memcmp(m_data, o.m_data, m_size * sizeof(unw_word_t));
    }
private:
    size_t m_size = 0;
    unw_word_t m_data[MAX_TRACE_SIZE];
};

namespace std {
    template<>
    struct hash<Trace>
    {
        size_t operator() (const Trace& trace) const
        {
            size_t seed = 0;
            for (auto ip : trace) {
                boost::hash_combine(seed, ip);
            }
            boost::hash_combine(seed, trace.size());
            return seed;
        }
    };
}

namespace {

using malloc_t = void* (*) (size_t);
using free_t = void (*) (void*);
using realloc_t = void* (*) (void*, size_t);
using calloc_t = void* (*) (size_t, size_t);
using posix_memalign_t = int (*) (void **, size_t, size_t);
using valloc_t = void* (*) (size_t);
using aligned_alloc_t = void* (*) (size_t, size_t);
using dlopen_t = void* (*) (const char*, int);

malloc_t real_malloc = nullptr;
free_t real_free = nullptr;
realloc_t real_realloc = nullptr;
calloc_t real_calloc = nullptr;
posix_memalign_t real_posix_memalign = nullptr;
valloc_t real_valloc = nullptr;
aligned_alloc_t real_aligned_alloc = nullptr;
dlopen_t real_dlopen = nullptr;

// threadsafe stuff
atomic<bool> moduleCacheDirty(true);

void trace(Trace& trace, const int skip = 2)
{
    trace.clear();

    unw_context_t uc;
    unw_getcontext (&uc);

    unw_cursor_t cursor;
    unw_init_local (&cursor, &uc);

    // skip functions we are not interested in
    for (int i = 0; i < skip; ++i) {
        if (unw_step(&cursor) <= 0) {
            return;
        }
    }

    while (unw_step(&cursor) > 0 && trace.size() < MAX_TRACE_SIZE) {
        unw_word_t ip;
        unw_get_reg(&cursor, UNW_REG_IP, &ip);
        if (!ip) {
            // this seems to happen regularly at the end of every trace and is useless to us
            // not also useless, its also quite slow to continue here into libunwind
            // I'll report this upstream.
            break;
        }
        trace.push_back(ip);
    }
}

struct HandleGuard
{
    HandleGuard()
        : wasLocked(inHandler)
    {
        inHandler = true;
    }

    ~HandleGuard()
    {
        inHandler = wasLocked;
    }

    const bool wasLocked;
    static thread_local bool inHandler;
};

thread_local bool HandleGuard::inHandler = false;

string env(const char* variable)
{
    const char* value = getenv(variable);
    return value ? string(value) : string();
}

struct Module
{
    string fileName;
    uintptr_t baseAddress;
    uint32_t size;
    unsigned int id;
    bool isExe;

    bool operator<(const Module& module) const
    {
        return make_tuple(baseAddress, size, fileName) < make_tuple(module.baseAddress, module.size, module.fileName);
    }
    bool operator!=(const Module& module) const
    {
        return make_tuple(baseAddress, size, fileName) != make_tuple(module.baseAddress, module.size, module.fileName);
    }
};

struct Data
{
    Data()
    {
        modules.reserve(32);
        ipCache.reserve(65536);
        traceCache.reserve(16384);
        allocationInfo.reserve(16384);

        string outputFileName = env("DUMP_MALLOC_TRACE_OUTPUT") + to_string(getpid());
        out = fopen(outputFileName.c_str(), "wa");
        if (!out) {
            fprintf(stderr, "Failed to open output file: %s\n", outputFileName.c_str());
            exit(1);
        }

        unsetenv("DUMP_MALLOC_TRACE_OUTPUT");
        unsetenv("LD_PRELOAD");
    }

    ~Data()
    {
        HandleGuard::inHandler = true;
        fclose(out);
    }

    void updateModuleCache()
    {
        // check list of loaded modules for unknown ones
        dl_iterate_phdr(dlopen_notify_callback, this);
        moduleCacheDirty = false;
    }

    /**
     * Mostly copied from vogl's src/libbacktrace/btrace.cpp
     */
    static int dlopen_notify_callback(struct dl_phdr_info *info, size_t /*size*/, void *_data)
    {
        auto data = reinterpret_cast<Data*>(_data);
        auto& modules = data->modules;
        bool isExe = false;
        const char *fileName = info->dlpi_name;
        const int BUF_SIZE = 1024;
        char buf[BUF_SIZE];
        // If we don't have a filename and we haven't added our main exe yet, do it now.
        if (!fileName || !fileName[0]) {
            if (modules.empty()) {
                isExe = true;
                ssize_t ret =  readlink("/proc/self/exe", buf, sizeof(buf));
                if ((ret > 0) && (ret < (ssize_t)sizeof(buf))) {
                    buf[ret] = 0;
                    fileName = buf;
                }
            }
            if (!fileName || !fileName[0]) {
                return 0;
            }
        }

        uintptr_t addressStart = 0;
        uintptr_t addressEnd = 0;

        for (int i = 0; i < info->dlpi_phnum; i++) {
            if (info->dlpi_phdr[i].p_type == PT_LOAD) {
                if (addressEnd == 0) {
                    addressStart = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
                    addressEnd = addressStart + info->dlpi_phdr[i].p_memsz;
                } else {
                    uintptr_t addr = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr + info->dlpi_phdr[i].p_memsz;
                    if (addr > addressEnd) {
                        addressEnd = addr;
                    }
                }
            }
        }

        Module module{fileName, addressStart, static_cast<uint32_t>(addressEnd - addressStart), 0, isExe};

        auto it = lower_bound(modules.begin(), modules.end(), module);
        if (it == modules.end() || *it != module) {
            module.id = data->next_module_id++;
            fprintf(data->out, "m %u %s %lx %d\n", module.id, module.fileName.c_str(), module.baseAddress, module.isExe);
            modules.insert(it, module);
        }

        return 0;
    }

    void handleMalloc(void* ptr, size_t size)
    {
        Trace traceBuffer;
        trace(traceBuffer);

        lock_guard<mutex> lock(m_mutex);
        if (moduleCacheDirty) {
            updateModuleCache();
        }
        auto it = traceCache.find(traceBuffer);
        if (it == traceCache.end()) {
            // cache before converting
            auto traceId = next_trace_id++;
            it = traceCache.insert(it, {traceBuffer, traceId});
            // ensure ip cache is up2date
            for (auto& ip : traceBuffer) {
                auto ipIt = ipCache.find(ip);
                if (ipIt == ipCache.end()) {
                    // find module and offset from cache
                    auto module = lower_bound(modules.begin(), modules.end(), ip,
                                                [] (const Module& module, const unw_word_t addr) -> bool {
                                                    return module.baseAddress + module.size < addr;
                                                });
                    if (module == modules.end()) {
                        ip = numeric_limits<unsigned int>::max();
                        continue;
                    }
                    auto ipId = next_ipCache_id++;
                    fprintf(out, "i %u %u %lx\n", ipId, module->id, ip - module->baseAddress);
                    ipIt = ipCache.insert(ipIt, {ip, ipId});
                }
                ip = ipIt->second;
            }
            // print trace
            fprintf(out, "t %u ", traceId);
            for (auto ipId : traceBuffer) {
                if (ipId == numeric_limits<unsigned int>::max()) {
                    continue;
                }
                fprintf(out, "%lu ", ipId);
            }
            fputc('\n', out);
        }
        allocationInfo[ptr] = {size, it->second};
        fprintf(out, "+ %lu %u\n", size, it->second);
    }

    void handleFree(void* ptr)
    {
        lock_guard<mutex> lock(m_mutex);
        auto it = allocationInfo.find(ptr);
        if (it == allocationInfo.end()) {
            return;
        }
        fprintf(out, "- %lu %u\n", it->second.size, it->second.traceId);
        allocationInfo.erase(it);
    }

    mutex m_mutex;
    unsigned int next_module_id = 0;
    unsigned int next_thread_id = 0;
    unsigned int next_ipCache_id = 0;
    unsigned int next_trace_id = 0;

    vector<Module> modules;
    unordered_map<unw_word_t, unw_word_t> ipCache;
    unordered_map<Trace, unsigned int> traceCache;
    struct AllocationInfo
    {
        size_t size;
        unsigned int traceId;
    };
    unordered_map<void*, AllocationInfo> allocationInfo;
    FILE* out = nullptr;
};

unique_ptr<Data> data;

template<typename T>
T findReal(const char* name)
{
    auto ret = dlsym(RTLD_NEXT, name);
    if (!ret) {
        fprintf(stderr, "Could not find original function %s\n", name);
        abort();
    }
    return reinterpret_cast<T>(ret);
}

/**
 * Dummy implementation, since the call to dlsym from findReal triggers a call to calloc.
 *
 * This is only called at startup and will eventually be replaced by the "proper" calloc implementation.
 */
void* dummy_calloc(size_t num, size_t size)
{
    const size_t MAX_SIZE = 1024;
    static char* buf[MAX_SIZE];
    static size_t offset = 0;
    if (!offset) {
        memset(buf, 0, MAX_SIZE);
    }
    size_t oldOffset = offset;
    offset += num * size;
    if (offset >= MAX_SIZE) {
        fprintf(stderr, "failed to initialize, dummy calloc buf size exhausted: %lu requested, %lu available\n", offset, MAX_SIZE);
        abort();
    }
    return buf + oldOffset;
}

void init()
{
    if (data || HandleGuard::inHandler) {
        fprintf(stderr, "initialization recursion detected\n");
        abort();
    }

    HandleGuard guard;

    real_calloc = &dummy_calloc;
    real_calloc = findReal<calloc_t>("calloc");
    real_dlopen = findReal<dlopen_t>("dlopen");
    real_malloc = findReal<malloc_t>("malloc");
    real_free = findReal<free_t>("free");
    real_realloc = findReal<realloc_t>("realloc");
    real_posix_memalign = findReal<posix_memalign_t>("posix_memalign");
    real_valloc = findReal<valloc_t>("valloc");
    real_aligned_alloc = findReal<aligned_alloc_t>("aligned_alloc");

    data.reset(new Data);
}

}

extern "C" {

/// TODO: memalign, pvalloc, ...?

void* malloc(size_t size)
{
    if (!real_malloc) {
        init();
    }

    void* ret = real_malloc(size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(ret, size);
    }

    return ret;
}

void free(void* ptr)
{
    if (!real_free) {
        init();
    }

    real_free(ptr);

    if (ptr && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleFree(ptr);
    }
}

void* realloc(void* ptr, size_t size)
{
    if (!real_realloc) {
        init();
    }

    void* ret = real_realloc(ptr, size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleFree(ptr);
        data->handleMalloc(ret, size);
    }

    return ret;
}

void* calloc(size_t num, size_t size)
{
    if (!real_calloc) {
        init();
    }

    void* ret = real_calloc(num, size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(ret, num*size);
    }

    return ret;
}

int posix_memalign(void **memptr, size_t alignment, size_t size)
{
    if (!real_posix_memalign) {
        init();
    }

    int ret = real_posix_memalign(memptr, alignment, size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(*memptr, size);
    }

    return ret;
}

void* aligned_alloc(size_t alignment, size_t size)
{
    if (!real_aligned_alloc) {
        init();
    }

    void* ret = real_aligned_alloc(alignment, size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(ret, size);
    }

    return ret;
}

void* valloc(size_t size)
{
    if (!real_valloc) {
        init();
    }

    void* ret = real_valloc(size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(ret, size);
    }

    return ret;
}

void *dlopen(const char *filename, int flag)
{
    if (!real_dlopen) {
        init();
    }

    void* ret = real_dlopen(filename, flag);

    if (ret) {
        moduleCacheDirty = true;
    }

    return ret;
}

}
<|endoftext|>


<commit_before>#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <d2d1.h>
#pragma comment(lib, "d2d1")

#include "../../../Nova/nova_geometry.h"
#include "../../../Nova/nova_render.h"

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

// Direct 2D vars.
ID2D1Factory *pFactory = NULL;
ID2D1HwndRenderTarget *pRenderTarget = NULL;
ID2D1Bitmap *bm = NULL;
ID2D1SolidColorBrush *pBrush = NULL;
HRESULT CreateD2D(HWND hWnd);
void DestroyD2D();

// My vars.
Mesh *mesh;
Matrix pos, persp;

void draw_line_D2D(float x0, float y0, float x1, float y1)
{
	D2D1_POINT_2F p0 = { x0, y0 };
	D2D1_POINT_2F p1 = { x1, y1 };
	pRenderTarget->DrawLine(p0, p1, pBrush);
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR pCmdLine, int nCmdShow)
{
	// Register the window class.
	WNDCLASS wc = { 0 };
	wc.lpfnWndProc = WindowProc;
	wc.hInstance = hInstance;
	wc.lpszClassName = L"Nova Window";
	RegisterClass(&wc);

	// Create the window.
	HWND hWnd = CreateWindowEx(0, wc.lpszClassName, L"Nova", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 600, 600, NULL, NULL, hInstance, NULL);
	if (hWnd == NULL)
		return -1;
	ShowWindow(hWnd, nCmdShow);

	if (FAILED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pFactory)))
		return -1;

	// Set up my stuff.
	mesh = CreateMeshFromFile("../../../models/bunny-5000.obj");
	if (!mesh)
		MessageBox(NULL, L"ERROR", L"Unable to load mesh file!", MB_OK);
	draw_line = draw_line_D2D;
	MatSetTranslate(&pos, 0.0f, -0.1f, -0.3f);

	// Run the message loop.
	MSG msg = { 0 };
	DWORD start = GetTickCount();
	DWORD now;
	int frame = 0;
	wchar_t d[20];
	while (msg.message != WM_QUIT)
	{
		while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		InvalidateRect(hWnd, NULL, FALSE);

		frame++;
		now = GetTickCount();
		if (now - start > 2000)
		{
			start = now;
			_itow_s(frame / 2, d, 20, 10);
			SetWindowText(hWnd, d);
			frame = 0;
		}
	}

	if (pFactory)
	{
		pFactory->Release();
		pFactory = NULL;
	}
	DestroyD2D();
	DestroyMesh(mesh);

	return 0;
}

HRESULT CreateD2D(HWND hWnd)
{
	HRESULT hr = S_OK;

	if (pRenderTarget == NULL)
	{
		RECT rc;
		GetClientRect(hWnd, &rc);

		D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);

		hr = pFactory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(), D2D1::HwndRenderTargetProperties(hWnd, size, D2D1_PRESENT_OPTIONS_IMMEDIATELY), &pRenderTarget);

		if (SUCCEEDED(hr))
		{
			const D2D1_COLOR_F color = D2D1::ColorF(0.0f, 0.0f, 0.0f);
			hr = pRenderTarget->CreateSolidColorBrush(color, &pBrush);
		}
	}

	return hr;
}

void DestroyD2D()
{
	if (pRenderTarget)
	{
		pRenderTarget->Release();
		pRenderTarget = NULL;
	}
	if (pBrush)
	{
		pBrush->Release();
		pBrush = NULL;
	}
}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_CREATE:

		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);

		return 0;

	case WM_PAINT:
	{
		if (pRenderTarget == NULL)
		{
			CreateD2D(hWnd);

			D2D1_PIXEL_FORMAT pf = pRenderTarget->GetPixelFormat();
			float dpix, dpiy;
			pRenderTarget->GetDpi(&dpix, &dpiy);
			D2D1_BITMAP_PROPERTIES bmp = D2D1::BitmapProperties(pf, dpix, dpiy);
			RECT rc;
			GetClientRect(hWnd, &rc);
			pRenderTarget->CreateBitmap(D2D1::SizeU(rc.right, rc.bottom), bmp, &bm);
		}

		PAINTSTRUCT ps;
		HDC hdc = BeginPaint(hWnd, &ps);

		pRenderTarget->BeginDraw();

		clear_pixel_buffer();
		clear_depth_buffer();

		if (mesh != NULL)
			RenderMesh(mesh, &pos);

		RECT rc;
		GetClientRect(hWnd, &rc);
		D2D1_RECT_U rect = D2D1::RectU(0, 0, rc.right, rc.bottom);
		uint32_t *src = get_pixel_buffer();
		HRESULT hr = bm->CopyFromMemory(NULL, src, rc.right * sizeof(uint32_t));
		pRenderTarget->DrawBitmap(bm);

		hr = pRenderTarget->EndDraw();
		if (FAILED(hr) || hr == D2DERR_RECREATE_TARGET)
			DestroyD2D();

		EndPaint(hWnd, &ps);
	}
	return 0;

	case WM_SIZE:
		RECT rc;
		GetClientRect(hWnd, &rc);

		if (pRenderTarget)
		{
			D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);
			pRenderTarget->Resize(size);
			InvalidateRect(hWnd, NULL, FALSE);
		}

		set_screen_size(rc.right, rc.bottom);
		set_fov(60.0f);

		return 0;
	}

	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
<commit_msg>Refactored support for Win32 window resizing<commit_after>#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <d2d1.h>
#pragma comment(lib, "d2d1")

#include "../../../Nova/nova_geometry.h"
#include "../../../Nova/nova_render.h"

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

// Direct 2D vars.
ID2D1Factory *pFactory = NULL;
ID2D1HwndRenderTarget *pRenderTarget = NULL;
ID2D1Bitmap *bm = NULL;
HRESULT CreateD2D(HWND hWnd);
void DestroyD2D();

// My vars.
Mesh *mesh;
Matrix pos, persp;

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR pCmdLine, int nCmdShow)
{
	// Register the window class.
	WNDCLASS wc = { 0 };
	wc.lpfnWndProc = WindowProc;
	wc.hInstance = hInstance;
	wc.lpszClassName = L"Nova Window";
	RegisterClass(&wc);

	// Create the window.
	HWND hWnd = CreateWindowEx(0, wc.lpszClassName, L"Nova", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 600, 600, NULL, NULL, hInstance, NULL);
	if (hWnd == NULL)
		return -1;
	ShowWindow(hWnd, nCmdShow);

	if (FAILED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pFactory)))
		return -1;

	// Set up my stuff.
	mesh = CreateMeshFromFile("../../../models/bunny-1500.obj");
	if (!mesh)
		MessageBox(NULL, L"ERROR", L"Unable to load mesh file!", MB_OK);

	MatSetTranslate(&pos, 0.0f, -0.1f, -0.3f);

	// Run the message loop.
	MSG msg = { 0 };
	DWORD start = GetTickCount();
	DWORD now;
	int frame = 0;
	wchar_t d[20];
	while (msg.message != WM_QUIT)
	{
		while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		InvalidateRect(hWnd, NULL, FALSE);

		frame++;
		now = GetTickCount();
		if (now - start > 2000)
		{
			start = now;
			_itow_s(frame / 2, d, 20, 10);
			SetWindowText(hWnd, d);
			frame = 0;
		}
	}

	if (pFactory)
	{
		pFactory->Release();
		pFactory = NULL;
	}

	DestroyD2D();
	DestroyMesh(mesh);

	return 0;
}

HRESULT CreateD2D(HWND hWnd)
{
	HRESULT hr = S_OK;

	if (pRenderTarget == NULL)
	{
		RECT rc;
		GetClientRect(hWnd, &rc);

		D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);

		hr = pFactory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(), D2D1::HwndRenderTargetProperties(hWnd, size, D2D1_PRESENT_OPTIONS_IMMEDIATELY), &pRenderTarget);

		if (SUCCEEDED(hr))
		{
			D2D1_PIXEL_FORMAT pf = pRenderTarget->GetPixelFormat();
			D2D1_BITMAP_PROPERTIES bmp = D2D1::BitmapProperties(pf);
			hr = pRenderTarget->CreateBitmap(pRenderTarget->GetPixelSize(), bmp, &bm);
		}
	}

	return hr;
}

void DestroyD2D()
{
	if (pRenderTarget != NULL)
	{
		pRenderTarget->Release();
		pRenderTarget = NULL;
	}
	if (bm != NULL)
	{
		bm->Release();
		bm = NULL;
	}
}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_CREATE:

		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);

		return 0;

	case WM_PAINT:
	{
		if (pRenderTarget == NULL)
		{
			CreateD2D(hWnd);

			D2D1_PIXEL_FORMAT pf = pRenderTarget->GetPixelFormat();
			float dpix, dpiy;
			pRenderTarget->GetDpi(&dpix, &dpiy);
			D2D1_BITMAP_PROPERTIES bmp = D2D1::BitmapProperties(pf, dpix, dpiy);
			RECT rc;
			GetClientRect(hWnd, &rc);
			pRenderTarget->CreateBitmap(D2D1::SizeU(rc.right, rc.bottom), bmp, &bm);
		}

		PAINTSTRUCT ps;
		HDC hdc = BeginPaint(hWnd, &ps);

		pRenderTarget->BeginDraw();

		clear_pixel_buffer();
		clear_depth_buffer();

		if (mesh != NULL)
			RenderMesh(mesh, &pos);

		RECT rc;
		GetClientRect(hWnd, &rc);
		D2D1_RECT_U rect = D2D1::RectU(0, 0, rc.right, rc.bottom);
		uint32_t *src = get_pixel_buffer();
		HRESULT hr = bm->CopyFromMemory(NULL, src, rc.right * sizeof(uint32_t));
		pRenderTarget->DrawBitmap(bm);

		hr = pRenderTarget->EndDraw();
		if (hr == D2DERR_RECREATE_TARGET)
			DestroyD2D();

		EndPaint(hWnd, &ps);
	}
	return 0;

	case WM_SIZE:
		RECT rc;
		GetClientRect(hWnd, &rc);

		DestroyD2D();

		set_screen_size(rc.right, rc.bottom);
		set_fov(60.0f);

		return 0;
	}

	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
<|endoftext|>


<commit_before>#include "include/vkalloc.h"<commit_msg>Define vka namespace<commit_after>#include "include/vkalloc.h"

#include <vector>
#include <unordered_map>

namespace vka {
    struct Page {
        VkDeviceMemory deviceMemory;
        Node* head = nullptr;
    };

    struct Node {
        Node* next = nullptr;
        uint64_t offset;
        uint64_t size;
    };

    VkPhysicalDevice physicalDevice;
    VkDevice device;
    VkPhysicalDeviceMemoryProperties properties;
    std::unordered_map<VkDeviceMemory, int32_t> pageMap;
    std::vector<Page> heaps[32];    //32 possible heaps
}

void vkaInit(VkPhysicalDevice physicalDevice, VkDevice device){

}

using namespace vka;

void vkaTerminate(){

}

VkAllocation vkAlloc(VkMemoryRequirements requirements){

}

void vkFree(VkAllocation allocation){

}

VkAllocation vkHostAlloc(VkMemoryRequirements requirements){

}

void vkHostFree(VkAllocation allocation){

}<|endoftext|>


<commit_before>

#include <string.h>

int main()
{
	printf("Hello World!");
	printf("Patrick");

	printf("Simon")
	return NULL;
}
<commit_msg>test provoke conflict<commit_after>

#include <string.h>

int main()
{
	printf("Hello World!");
	printf("Patrick");

	printf("RIOT");
	printf("Simon");
	return NULL;
}
<|endoftext|>


<commit_before>/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
/**
 * @author Alexander V. Astapchuk
 * @version $Revision: $
 */

/**
 * @file
 * @brief Main decoding (disassembling) routines implementation.
 */

#include "dec_base.h"
#include "open/common.h"

bool DecoderBase::is_prefix(const unsigned char * bytes)
{
    unsigned char b0 = *bytes;
    unsigned char b1 = *(bytes+1);
    if (b0 == 0xF0) { // LOCK
        return true;
    }
    if (b0==0xF2 || b0==0xF3) { // REPNZ/REPZ prefixes
        if (b1 == 0x0F) {   // .... but may be a part of SIMD opcode
            return false;
        }
        return true;
    }
    if (b0 == 0x2E || b0 == 0x36 || b0==0x3E || b0==0x26 || b0==0x64 || b0==0x3E) {
        // branch hints, segment prefixes
        return true;
    }
    if (b0==0x66) { // operand-size prefix
        if (b1 == 0x0F) {   // .... but may be a part of SIMD opcode
            return false;
        }
        return false; //XXX - currently considered as part of opcode//true;
    }
    if (b0==0x67) { // address size prefix
        return true;
    }
    return false;
}

unsigned DecoderBase::decode(const void * addr, Inst * pinst)
{
    Inst tmp;

    //assert( *(unsigned char*)addr != 0x66);

    const unsigned char * bytes = (unsigned char*)addr;
    // Check prefix first
    for (unsigned i=0; i<4; i++) {
        if (!is_prefix(bytes)) {
            break;
        }
        ++bytes;
    }

    if (is_prefix(bytes)) {
        // More than 4 prefixes together ?
//        assert(false);
        return 0;
    }

    // Load up to 4 prefixes
    // for each Mnemonic
    //  for each opcodedesc
    //      if (raw_len == 0) memcmp(, raw_len)
    //  else check the mixed state which is one of the following:
    //      /digit /i /rw /rd /rb

    bool found = false;
    const unsigned char * saveBytes = bytes;
    for (unsigned mn=1; mn<Mnemonic_Count; mn++) {
        bytes = saveBytes;
        found=try_mn((Mnemonic)mn, &bytes, &tmp);
        if (found) {
            tmp.mn = (Mnemonic)mn;
            break;
        }
    }
    if (!found) {
//        assert(false);
        return 0;
    }
    tmp.size = (unsigned)(bytes-(const unsigned char*)addr);
    if (pinst) {
        *pinst = tmp;
    }
    return tmp.size;
}

#ifdef _EM64T_
#define EXTEND_REG(reg, flag)                        \
    ((NULL == rex || 0 == rex->flag) ? reg : (reg + 8))
#else
#define EXTEND_REG(reg, flag) (reg)
#endif

bool DecoderBase::decode_aux(const EncoderBase::OpcodeDesc& odesc, unsigned aux,
    const unsigned char ** pbuf, Inst * pinst, const Rex UNREF *rex)
{
    OpcodeByteKind kind = (OpcodeByteKind)(aux & OpcodeByteKind_KindMask);
    unsigned byte = (aux & OpcodeByteKind_OpcodeMask);
    unsigned data_byte = **pbuf;
    EncoderBase::Operand& opnd = pinst->operands[pinst->argc];
    const EncoderBase::OpndDesc& opndDesc = odesc.opnds[pinst->argc];

    switch (kind) {
    case OpcodeByteKind_SlashR:
        //decodeModRM(odesc, pbuf, pinst);
        {
        const ModRM& modrm = *(ModRM*)*pbuf;
        unsigned regIndex = odesc.opnds[0].kind == OpndKind_GPReg ? 0 : 1;
        RegName reg = getRegName(OpndKind_GPReg, opndDesc.size, EXTEND_REG(modrm.reg, r));
        EncoderBase::Operand& regOpnd = pinst->operands[regIndex];
        if (regIndex == 0) {
            regOpnd = EncoderBase::Operand(reg);
            ++pinst->argc;
            decodeModRM(odesc, pbuf, pinst, rex);
        }
        else {
            decodeModRM(odesc, pbuf, pinst, rex);
            ++pinst->argc;
            regOpnd = EncoderBase::Operand(reg);
        }
        ++pinst->argc;
        }
        return true;
    case OpcodeByteKind_rb:
    case OpcodeByteKind_rw:
    case OpcodeByteKind_rd:
        {
            // Gregory -
            // Here we don't parse register because for current needs
            // disassembler doesn't require to parse all operands
            unsigned regid = data_byte - byte;
            if (regid>7) {
                return false;
            }
            ++*pbuf;
            return true;
        }
    case OpcodeByteKind_cb:
        {
        char offset = *(char*)*pbuf;
        *pbuf += 1;
        opnd = EncoderBase::Operand(offset);
        ++pinst->argc;
        //pinst->direct_addr = (void*)(pinst->offset + *pbuf);
        }
        return true;
    case OpcodeByteKind_cw:
//        assert(false); // not an error, but not expected in current env
        break;
    case OpcodeByteKind_cd:
        {
        int offset = *(int*)*pbuf;
        *pbuf += 4;
        opnd = EncoderBase::Operand(offset);
        ++pinst->argc;
        }
        return true;
    case OpcodeByteKind_SlashNum:
        {
        const ModRM& modrm = *(ModRM*)*pbuf;
        if (modrm.reg != byte) {
            return false;
        }
        decodeModRM(odesc, pbuf, pinst, rex);
        ++pinst->argc;
        }
        return true;
    case OpcodeByteKind_ib:
        {
        char ival = *(char*)*pbuf;
        opnd = EncoderBase::Operand(ival);
        ++pinst->argc;
        *pbuf += 1;
        }
        return true;
    case OpcodeByteKind_iw:
        {
        short ival = *(short*)*pbuf;
        opnd = EncoderBase::Operand(ival);
        ++pinst->argc;
        *pbuf += 2;
        }
        return true;
    case OpcodeByteKind_id:
        {
        int ival = *(int*)*pbuf;
        opnd = EncoderBase::Operand(ival);
        ++pinst->argc;
        *pbuf += 4;
        }
        return true;
#ifdef _EM64T_
    case OpcodeByteKind_io:
        {
        long long int ival = *(long long int*)*pbuf;
        opnd = EncoderBase::Operand(OpndSize_64, ival);
        ++pinst->argc;
        *pbuf += 8;
        }
        return true;
#endif
    case OpcodeByteKind_plus_i:
        {
            unsigned regid = data_byte - byte;
            if (regid>7) {
                return false;
            }
            ++*pbuf;
            return true;
        }
    case OpcodeByteKind_ZeroOpcodeByte: // cant be here
//        assert(false);
        break;
    default:
        // unknown kind ? how comes ?
//        assert(false);
        break;
    }
    return false;
}

bool DecoderBase::try_mn(Mnemonic mn, const unsigned char ** pbuf, Inst * pinst) {
    const unsigned char * save_pbuf = *pbuf;
    EncoderBase::OpcodeDesc * opcodes = EncoderBase::opcodes[mn];

    for (unsigned i=0; !opcodes[i].last; i++) {
        const EncoderBase::OpcodeDesc& odesc = opcodes[i];
        char *opcode_ptr = const_cast<char *>(odesc.opcode);
        int opcode_len = odesc.opcode_len;
        Rex *prex = NULL;
#ifdef _EM64T_
        Rex rex;
#endif

        *pbuf = save_pbuf;
#ifdef _EM64T_
        // Match REX prefixes
        unsigned char rex_byte = (*pbuf)[0];
        if ((rex_byte & 0xf0) == 0x40)
        {
            if ((rex_byte & 0x08) != 0)
            {
                // Have REX.W
                if (opcode_len > 0 && opcode_ptr[0] == 0x48)
                {
                    // Have REX.W in opcode. All mnemonics that allow
                    // REX.W have to have specified it in opcode,
                    // otherwise it is not allowed
                    rex = *(Rex *)*pbuf;
                    prex = &rex;
                    (*pbuf)++;
                    opcode_ptr++;
                    opcode_len--;
                }
            }
            else
            {
                // No REX.W, so it doesn't have to be in opcode. We
                // have REX.B, REX.X, REX.R or their combination, but
                // not in opcode, they may extend any part of the
                // instruction
                rex = *(Rex *)*pbuf;
                prex = &rex;
                (*pbuf)++;
            }
        }
#endif
        if (opcode_len != 0) {
            if (memcmp(*pbuf, opcode_ptr, opcode_len)) {
                continue;
            }
            *pbuf += opcode_len;
        }
        if (odesc.aux0 != 0) {

            if (!decode_aux(odesc, odesc.aux0, pbuf, pinst, prex)) {
                continue;
            }
            if (odesc.aux1 != 0) {
                if (!decode_aux(odesc, odesc.aux1, pbuf, pinst, prex)) {
                    continue;
                }
            }
            pinst->odesc = &opcodes[i];
            return true;
        }
        else {
            // Can't have empty opcode
            assert(opcode_len != 0);
            pinst->odesc = &opcodes[i];
            return true;
        }
    }
    return false;
}

bool DecoderBase::decodeModRM(const EncoderBase::OpcodeDesc& odesc,
    const unsigned char ** pbuf, Inst * pinst, const Rex *rex)
{
    EncoderBase::Operand& opnd = pinst->operands[pinst->argc];
    const EncoderBase::OpndDesc& opndDesc = odesc.opnds[pinst->argc];

    //XXX debug ///assert(0x66 != *(*pbuf-2));
    const ModRM& modrm = *(ModRM*)*pbuf;
    *pbuf += 1;

    RegName base = RegName_Null;
    RegName index = RegName_Null;
    int disp = 0;
    unsigned scale = 0;
    OpndSize reg_size = OpndSize_32;

#ifdef _EM64T_
    if (NULL != rex && 0 != rex->w)
        reg_size = OpndSize_64;
#endif

    if (modrm.mod == 3) {
        // we have only modrm. no sib, no disp.
        RegName reg = getRegName(OpndKind_GPReg, opndDesc.size, EXTEND_REG(modrm.rm, b));
        opnd = EncoderBase::Operand(reg);
        return true;
    }
    const SIB& sib = *(SIB*)*pbuf;
    // check whether we have a sib
    if (modrm.rm == 4) {
        // yes, we have SIB
        *pbuf += 1;
        scale = sib.scale == 0 ? 0 : (1<<sib.scale);
        if (sib.index != 4) {
			index = getRegName(OpndKind_GPReg, reg_size, EXTEND_REG(sib.index, x));
        } else {
            // (sib.index == 4) => no index
        }

        if (sib.base != 5 && modrm.mod != 0) {
            base = getRegName(OpndKind_GPReg, reg_size, EXTEND_REG(sib.base, b));
        } else {
            // (sib.base == 5 && modrm.mod == 0) => no base
        }
    }
    else {
        if (modrm.mod != 0 || modrm.rm != 5) {
            base = getRegName(OpndKind_GPReg, reg_size, EXTEND_REG(modrm.rm, b));
        }
        else {
            // mod=0 && rm == 5 => only disp32
        }
    }

    if (modrm.mod == 2) {
        // have disp32
        disp = *(int*)*pbuf;
        *pbuf += 4;
    }
    else if (modrm.mod == 1) {
        // have disp8
        disp = *(char*)*pbuf;
        *pbuf += 1;
    }
    else {
        assert(modrm.mod == 0);
        if (modrm.rm == 5) {
            // have disp32 w/o sib
            disp = *(int*)*pbuf;
            *pbuf += 4;
        }
        else if (modrm.rm == 4 && sib.base == 5) {
            // have disp32 with SI in sib
            disp = *(int*)*pbuf;
            *pbuf += 4;
        }
    }
    opnd = EncoderBase::Operand(opndDesc.size, base, index, scale, disp);
    return true;
}

<commit_msg>Applied patch from HARMONY-5510 [drlvm][jvmti] VTS test for SingleStep event fails on x86_64<commit_after>/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
/**
 * @author Alexander V. Astapchuk
 * @version $Revision: $
 */

/**
 * @file
 * @brief Main decoding (disassembling) routines implementation.
 */

#include "dec_base.h"
#include "open/common.h"

bool DecoderBase::is_prefix(const unsigned char * bytes)
{
    unsigned char b0 = *bytes;
    unsigned char b1 = *(bytes+1);
    if (b0 == 0xF0) { // LOCK
        return true;
    }
    if (b0==0xF2 || b0==0xF3) { // REPNZ/REPZ prefixes
        if (b1 == 0x0F) {   // .... but may be a part of SIMD opcode
            return false;
        }
        return true;
    }
    if (b0 == 0x2E || b0 == 0x36 || b0==0x3E || b0==0x26 || b0==0x64 || b0==0x3E) {
        // branch hints, segment prefixes
        return true;
    }
    if (b0==0x66) { // operand-size prefix
        if (b1 == 0x0F) {   // .... but may be a part of SIMD opcode
            return false;
        }
        return false; //XXX - currently considered as part of opcode//true;
    }
    if (b0==0x67) { // address size prefix
        return true;
    }
    return false;
}

unsigned DecoderBase::decode(const void * addr, Inst * pinst)
{
    Inst tmp;

    //assert( *(unsigned char*)addr != 0x66);

    const unsigned char * bytes = (unsigned char*)addr;
    // Check prefix first
    for (unsigned i=0; i<4; i++) {
        if (!is_prefix(bytes)) {
            break;
        }
        ++bytes;
    }

    if (is_prefix(bytes)) {
        // More than 4 prefixes together ?
//        assert(false);
        return 0;
    }

    // Load up to 4 prefixes
    // for each Mnemonic
    //  for each opcodedesc
    //      if (raw_len == 0) memcmp(, raw_len)
    //  else check the mixed state which is one of the following:
    //      /digit /i /rw /rd /rb

    bool found = false;
    const unsigned char * saveBytes = bytes;
    for (unsigned mn=1; mn<Mnemonic_Count; mn++) {
        bytes = saveBytes;
        found=try_mn((Mnemonic)mn, &bytes, &tmp);
        if (found) {
            tmp.mn = (Mnemonic)mn;
            break;
        }
    }
    if (!found) {
//        assert(false);
        return 0;
    }
    tmp.size = (unsigned)(bytes-(const unsigned char*)addr);
    if (pinst) {
        *pinst = tmp;
    }
    return tmp.size;
}

#ifdef _EM64T_
#define EXTEND_REG(reg, flag)                        \
    ((NULL == rex || 0 == rex->flag) ? reg : (reg + 8))
#else
#define EXTEND_REG(reg, flag) (reg)
#endif

bool DecoderBase::decode_aux(const EncoderBase::OpcodeDesc& odesc, unsigned aux,
    const unsigned char ** pbuf, Inst * pinst, const Rex UNREF *rex)
{
    OpcodeByteKind kind = (OpcodeByteKind)(aux & OpcodeByteKind_KindMask);
    unsigned byte = (aux & OpcodeByteKind_OpcodeMask);
    unsigned data_byte = **pbuf;
    EncoderBase::Operand& opnd = pinst->operands[pinst->argc];
    const EncoderBase::OpndDesc& opndDesc = odesc.opnds[pinst->argc];

    switch (kind) {
    case OpcodeByteKind_SlashR:
        //decodeModRM(odesc, pbuf, pinst);
        {
        const ModRM& modrm = *(ModRM*)*pbuf;
        unsigned regIndex = odesc.opnds[0].kind == OpndKind_GPReg ? 0 : 1;
        RegName reg = getRegName(OpndKind_GPReg, opndDesc.size, EXTEND_REG(modrm.reg, r));
        EncoderBase::Operand& regOpnd = pinst->operands[regIndex];
        if (regIndex == 0) {
            regOpnd = EncoderBase::Operand(reg);
            ++pinst->argc;
            decodeModRM(odesc, pbuf, pinst, rex);
        }
        else {
            decodeModRM(odesc, pbuf, pinst, rex);
            ++pinst->argc;
            regOpnd = EncoderBase::Operand(reg);
        }
        ++pinst->argc;
        }
        return true;
    case OpcodeByteKind_rb:
    case OpcodeByteKind_rw:
    case OpcodeByteKind_rd:
        {
            // Gregory -
            // Here we don't parse register because for current needs
            // disassembler doesn't require to parse all operands
            unsigned regid = data_byte - byte;
            if (regid>7) {
                return false;
            }
            ++*pbuf;
            return true;
        }
    case OpcodeByteKind_cb:
        {
        char offset = *(char*)*pbuf;
        *pbuf += 1;
        opnd = EncoderBase::Operand(offset);
        ++pinst->argc;
        //pinst->direct_addr = (void*)(pinst->offset + *pbuf);
        }
        return true;
    case OpcodeByteKind_cw:
//        assert(false); // not an error, but not expected in current env
        break;
    case OpcodeByteKind_cd:
        {
        int offset = *(int*)*pbuf;
        *pbuf += 4;
        opnd = EncoderBase::Operand(offset);
        ++pinst->argc;
        }
        return true;
    case OpcodeByteKind_SlashNum:
        {
        const ModRM& modrm = *(ModRM*)*pbuf;
        if (modrm.reg != byte) {
            return false;
        }
        decodeModRM(odesc, pbuf, pinst, rex);
        ++pinst->argc;
        }
        return true;
    case OpcodeByteKind_ib:
        {
        char ival = *(char*)*pbuf;
        opnd = EncoderBase::Operand(ival);
        ++pinst->argc;
        *pbuf += 1;
        }
        return true;
    case OpcodeByteKind_iw:
        {
        short ival = *(short*)*pbuf;
        opnd = EncoderBase::Operand(ival);
        ++pinst->argc;
        *pbuf += 2;
        }
        return true;
    case OpcodeByteKind_id:
        {
        int ival = *(int*)*pbuf;
        opnd = EncoderBase::Operand(ival);
        ++pinst->argc;
        *pbuf += 4;
        }
        return true;
#ifdef _EM64T_
    case OpcodeByteKind_io:
        {
        long long int ival = *(long long int*)*pbuf;
        opnd = EncoderBase::Operand(OpndSize_64, ival);
        ++pinst->argc;
        *pbuf += 8;
        }
        return true;
#endif
    case OpcodeByteKind_plus_i:
        {
            unsigned regid = data_byte - byte;
            if (regid>7) {
                return false;
            }
            ++*pbuf;
            return true;
        }
    case OpcodeByteKind_ZeroOpcodeByte: // cant be here
//        assert(false);
        break;
    default:
        // unknown kind ? how comes ?
//        assert(false);
        break;
    }
    return false;
}

bool DecoderBase::try_mn(Mnemonic mn, const unsigned char ** pbuf, Inst * pinst) {
    const unsigned char * save_pbuf = *pbuf;
    EncoderBase::OpcodeDesc * opcodes = EncoderBase::opcodes[mn];

    for (unsigned i=0; !opcodes[i].last; i++) {
        const EncoderBase::OpcodeDesc& odesc = opcodes[i];
        char *opcode_ptr = const_cast<char *>(odesc.opcode);
        int opcode_len = odesc.opcode_len;
        Rex *prex = NULL;
#ifdef _EM64T_
        Rex rex;
#endif

        *pbuf = save_pbuf;
#ifdef _EM64T_
        // Match REX prefixes
        unsigned char rex_byte = (*pbuf)[0];
        if ((rex_byte & 0xf0) == 0x40)
        {
            if ((rex_byte & 0x08) != 0)
            {
                // Have REX.W
                if (opcode_len > 0 && opcode_ptr[0] == 0x48)
                {
                    // Have REX.W in opcode. All mnemonics that allow
                    // REX.W have to have specified it in opcode,
                    // otherwise it is not allowed
                    rex = *(Rex *)*pbuf;
                    prex = &rex;
                    (*pbuf)++;
                    opcode_ptr++;
                    opcode_len--;
                }
            }
            else
            {
                // No REX.W, so it doesn't have to be in opcode. We
                // have REX.B, REX.X, REX.R or their combination, but
                // not in opcode, they may extend any part of the
                // instruction
                rex = *(Rex *)*pbuf;
                prex = &rex;
                (*pbuf)++;
            }
        }
#endif
        if (opcode_len != 0) {
            if (memcmp(*pbuf, opcode_ptr, opcode_len)) {
                continue;
            }
            *pbuf += opcode_len;
        }
        if (odesc.aux0 != 0) {

            if (!decode_aux(odesc, odesc.aux0, pbuf, pinst, prex)) {
                continue;
            }
            if (odesc.aux1 != 0) {
                if (!decode_aux(odesc, odesc.aux1, pbuf, pinst, prex)) {
                    continue;
                }
            }
            pinst->odesc = &opcodes[i];
            return true;
        }
        else {
            // Can't have empty opcode
            assert(opcode_len != 0);
            pinst->odesc = &opcodes[i];
            return true;
        }
    }
    return false;
}

bool DecoderBase::decodeModRM(const EncoderBase::OpcodeDesc& odesc,
    const unsigned char ** pbuf, Inst * pinst, const Rex *rex)
{
    EncoderBase::Operand& opnd = pinst->operands[pinst->argc];
    const EncoderBase::OpndDesc& opndDesc = odesc.opnds[pinst->argc];

    //XXX debug ///assert(0x66 != *(*pbuf-2));
    const ModRM& modrm = *(ModRM*)*pbuf;
    *pbuf += 1;

    RegName base = RegName_Null;
    RegName index = RegName_Null;
    int disp = 0;
    unsigned scale = 0;

    // On x86_64 all mnemonics that allow REX.W have REX.W in opcode.
    // Therefore REX.W is simply ignored, and opndDesc.size is used

    if (modrm.mod == 3) {
        // we have only modrm. no sib, no disp.
        RegName reg = getRegName(OpndKind_GPReg, opndDesc.size, EXTEND_REG(modrm.rm, b));
        opnd = EncoderBase::Operand(reg);
        return true;
    }
    const SIB& sib = *(SIB*)*pbuf;
    // check whether we have a sib
    if (modrm.rm == 4) {
        // yes, we have SIB
        *pbuf += 1;
        scale = sib.scale == 0 ? 0 : (1<<sib.scale);
        if (sib.index != 4) {
			index = getRegName(OpndKind_GPReg, opndDesc.size, EXTEND_REG(sib.index, x));
        } else {
            // (sib.index == 4) => no index
        }

        if (sib.base != 5 && modrm.mod != 0) {
            base = getRegName(OpndKind_GPReg, opndDesc.size, EXTEND_REG(sib.base, b));
        } else {
            // (sib.base == 5 && modrm.mod == 0) => no base
        }
    }
    else {
        if (modrm.mod != 0 || modrm.rm != 5) {
            base = getRegName(OpndKind_GPReg, opndDesc.size, EXTEND_REG(modrm.rm, b));
        }
        else {
            // mod=0 && rm == 5 => only disp32
        }
    }

    if (modrm.mod == 2) {
        // have disp32
        disp = *(int*)*pbuf;
        *pbuf += 4;
    }
    else if (modrm.mod == 1) {
        // have disp8
        disp = *(char*)*pbuf;
        *pbuf += 1;
    }
    else {
        assert(modrm.mod == 0);
        if (modrm.rm == 5) {
            // have disp32 w/o sib
            disp = *(int*)*pbuf;
            *pbuf += 4;
        }
        else if (modrm.rm == 4 && sib.base == 5) {
            // have disp32 with SI in sib
            disp = *(int*)*pbuf;
            *pbuf += 4;
        }
    }
    opnd = EncoderBase::Operand(opndDesc.size, base, index, scale, disp);
    return true;
}

<|endoftext|>


<commit_before>#ifndef VIENNAGRID_META_TYPELIST_HPP
#define VIENNAGRID_META_TYPELIST_HPP

#include "utils.hpp"

namespace viennagrid
{
  namespace meta
  {

    template <class head_, class tail_>
    struct typelist_t
    {
       typedef head_ head;
       typedef tail_ tail;
    };

//     C++11 version

//     template<typename ... types>
//     struct make_typelist;
//
//     template<>
//     struct make_typelist<>
//     {
//         typedef viennagrid::meta::null_type type;
//     };
//
//     template<typename head, typename ... tail>
//     struct make_typelist<head, tail...>
//     {
//         typedef viennagrid::meta::typelist_t<head, typename make_typelist<tail...>::type> type;
//     };

    template<   typename T01 = viennagrid::meta::null_type, typename T02 = viennagrid::meta::null_type, typename T03 = viennagrid::meta::null_type, typename T04 = viennagrid::meta::null_type,
                typename T05 = viennagrid::meta::null_type, typename T06 = viennagrid::meta::null_type, typename T07 = viennagrid::meta::null_type, typename T08 = viennagrid::meta::null_type,
                typename T09 = viennagrid::meta::null_type, typename T10 = viennagrid::meta::null_type, typename T11 = viennagrid::meta::null_type, typename T12 = viennagrid::meta::null_type,
                typename T13 = viennagrid::meta::null_type, typename T14 = viennagrid::meta::null_type, typename T15 = viennagrid::meta::null_type, typename T16 = viennagrid::meta::null_type,
                typename T17 = viennagrid::meta::null_type, typename T18 = viennagrid::meta::null_type, typename T19 = viennagrid::meta::null_type, typename T20 = viennagrid::meta::null_type >
    struct make_typelist
    {
        typedef
            typelist_t<
                T01,
                typename make_typelist<T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20>::type
            > type;
    };

    template<>
    struct make_typelist<
        viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type,
        viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type,
        viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type,
        viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type,
        viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type>
    {
        typedef viennagrid::meta::null_type type;
    };

    namespace typelist
    {

        namespace result_of
        {

            // size of a typelist
            template <typename typelist> struct size;

            template <> struct size<null_type>
            {
                enum { value = 0 };
            };

            template <typename head, typename tail>
            struct size< typelist_t<head, tail> >
            {
                enum { value = 1 + size<tail>::value };
            };

            // index access
            template <typename typelist, unsigned int index> struct at
            {
                typedef out_of_range type;
            };

            template <typename head, typename tail>
            struct at<typelist_t<head, tail>, 0>
            {
                typedef head type;
            };

            template <typename head, typename tail, unsigned int i>
            struct at<typelist_t<head, tail>, i>
            {
                typedef typename at<tail, i - 1>::type type;
            };

            // returns the index of the first type in the typelist
            template <typename typelist, typename to_find> struct index_of;

            template <typename to_find>
            struct index_of<null_type, to_find>
            {
                enum { value = -1 };
            };

            template <typename to_find, typename tail>
            struct index_of<typelist_t<to_find, tail>, to_find>
            {
                enum { value = 0 };
            };

            template <typename head, typename tail, typename to_find>
            struct index_of<typelist_t<head, tail>, to_find>
            {
            private:
                enum { temp = index_of<tail, to_find>::value };
            public:
                enum { value = (temp == -1 ? -1 : 1 + temp) };
            };

            // push back a single type
            template <typename typelist, typename to_add> struct push_back;

            template <>
            struct push_back<null_type, null_type>
            {
                typedef null_type type;
            };

            template <typename to_add>
            struct push_back<null_type, to_add>
            {
                typedef typelist_t<to_add, null_type> type;
            };

            template <typename head, typename tail, typename to_add>
            struct push_back<typelist_t<head, tail>, to_add>
            {
                typedef typelist_t<head, typename push_back<tail, to_add>::type> type;
            };

            // push back list
            template <typename typelist, typename typelist_to_add> struct push_back_list;

            template <>
            struct push_back_list<null_type, null_type>
            {
                typedef null_type type;
            };

            template <typename head, typename tail>
            struct push_back_list<null_type, typelist_t<head, tail> >
            {
                typedef typelist_t<head, tail> type;
            };

            template <typename head, typename tail>
            struct push_back_list<typelist_t<head, tail>, null_type >
            {
                typedef typelist_t<head, tail> type;
            };

            template <typename head1, typename tail1, typename head2, typename tail2>
            struct push_back_list<typelist_t<head1, tail1>, typelist_t<head2, tail2> >
            {
                typedef typename push_back_list< typename push_back< typelist_t<head1, tail1>, head2>::type, tail2 >::type type;
            };

            // erase_at the type at index
            template <typename typelist, unsigned int index_to_erase> struct erase_at;

            template <unsigned int index_to_erase>
            struct erase_at<null_type, index_to_erase>
            {
                typedef null_type type;
            };

            template <typename head, typename tail>
            struct erase_at< typelist_t<head, tail>, 0>
            {
                typedef tail type;
            };

            template <typename head, typename tail, unsigned int index_to_erase>
            struct erase_at< typelist_t<head, tail>, index_to_erase>
            {
                typedef typelist_t<head, typename erase_at<tail, index_to_erase-1>::type> type;
            };

            // erase the first type
            template <typename typelist, typename to_erase> struct erase;

            template <typename to_erase>
            struct erase<null_type, to_erase>
            {
                typedef null_type type;
            };

            template <typename to_erase, typename tail>
            struct erase< typelist_t<to_erase, tail>, to_erase>
            {
                typedef tail type;
            };

            template <typename head, typename tail, typename to_erase>
            struct erase< typelist_t<head, tail>, to_erase>
            {
                typedef typelist_t<head, typename erase<tail, to_erase>::type> type;
            };

            // erase all types
            template <typename typelist, typename to_erase>
            struct erase_all;

            template <typename to_erase>
            struct erase_all<null_type, to_erase>
            {
                typedef null_type type;
            };

            template <typename to_erase, typename tail>
            struct erase_all< typelist_t<to_erase, tail>, to_erase>
            {
                // Go all the way down the list removing the type
                typedef typename erase_all<tail, to_erase>::type type;
            };
            template <typename head, typename tail, typename to_erase>

            struct erase_all< typelist_t<head, tail>, to_erase>
            {
                // Go all the way down the list removing the type
                typedef typelist_t<head, typename erase_all<tail, to_erase>::type> type;
            };

            // reverse
            template <typename typelist> struct reverse;

            template <> struct
            reverse<null_type>
            {
                typedef null_type type;
            };

            template <typename head, typename tail>
            struct reverse< typelist_t<head, tail> >
            {
            public:
                typedef typelist_t<head, tail> typelist;

                typedef typelist_t<
                    typename at<
                      typelist,
                      size<typelist>::value-1
                    >::type,
                    typename erase_at<
                      typelist,
                      size<typelist>::value-1
                    >::type
                > type;
            };

            // no duplicate types
            template <typename typelist> struct no_duplicates;

            template <> struct
            no_duplicates<null_type>
            {
                typedef null_type type;
            };

            template <typename head, typename tail>
            struct no_duplicates< typelist_t<head, tail> >
            {
            private:
                typedef typename no_duplicates<tail>::type L1;
                typedef typename erase<L1, head>::type L2;
            public:
                typedef typelist_t<head, L2> type;
            };

            // replace the type at index by another type
            template <typename typelist, unsigned int index_to_replace, typename replaced> struct replace_at;

            template <unsigned int index_to_replace, typename replaced>
            struct replace_at<null_type, index_to_replace, replaced>
            {
                typedef null_type type;
            };

            template <typename head, typename tail, typename replaced>
            struct replace_at<typelist_t<head, tail>, 0, replaced>
            {
                typedef typelist_t<replaced, tail> type;
            };

            template <typename head, typename tail, unsigned int index_to_replace, typename replaced>
            struct replace_at<typelist_t<head, tail>, index_to_replace, replaced>
            {
                typedef typelist_t<head, typename replace_at<tail, index_to_replace-1, replaced>::type> type;
            };

            // replace the first type by another type
            template <typename typelist, typename to_replace, typename replaced> struct replace;

            template <typename to_replace, typename replaced>
            struct replace<null_type, to_replace, replaced>
            {
                typedef null_type type;
            };

            template <typename to_replace, typename tail, typename replaced>
            struct replace<typelist_t<to_replace, tail>, to_replace, replaced>
            {
                typedef typelist_t<replaced, tail> type;
            };

            template <typename head, typename tail, typename to_replace, typename replaced>
            struct replace<typelist_t<head, tail>, to_replace, replaced>
            {
                typedef typelist_t<head, typename replace<tail, to_replace, replaced>::type> type;
            };

            // replace all types by another type
            template <typename typelist, typename to_replace, typename replaced> struct replace_all;

            template <typename to_replace, typename replaced>
            struct replace_all<null_type, to_replace, replaced>
            {
                typedef null_type type;
            };

            template <typename to_replace, typename tail, typename replaced>
            struct replace_all<typelist_t<to_replace, tail>, to_replace, replaced>
            {
                typedef typelist_t<replaced, typename replace_all<tail, to_replace, replaced>::type> type;
            };

            template <typename head, typename tail, typename to_replace, typename replaced>
            struct replace_all<typelist_t<head, tail>, to_replace, replaced>
            {
                typedef typelist_t<head, typename replace_all<tail, to_replace, replaced>::type> type;
            };

            // returns only those types which are in both typelists
            template<typename typelist1, typename typelist2>
            struct intersection {};

           template<>
            struct intersection<null_type, null_type>
            {
                typedef null_type type;
            };

            template<typename head1, typename tail1>
            struct intersection<typelist_t<head1, tail1>, null_type>
            {
                typedef null_type type;
            };

            template<typename head2, typename tail2>
            struct intersection<null_type, typelist_t<head2, tail2> >
            {
                typedef null_type type;
            };

            template<typename head1, typename tail1, typename head2, typename tail2>
            struct intersection< typelist_t<head1, tail1>, typelist_t<head2, tail2> >
            {
                typedef typelist_t<head1, tail1> typelist1;
                typedef typelist_t<head2, tail2> typelist2;

                enum { search_result = index_of< typelist2, head1 >::value };

                typedef typename IF<
                    (search_result >= 0),
                    typename erase_at<typelist2, search_result>::type,
                    typelist2
                >::type new_typelist2;

                typedef typename IF<
                    (search_result >= 0),
                    typelist_t<head1, typename intersection<tail1, new_typelist2>::type >,
                    typename intersection<tail1, new_typelist2>::type
                >::type type;
            };

        }
    }
  } // namespace meta
} // namespace viennagrid

#endif // end file guardian
<commit_msg>fixed bug in reverse meta function<commit_after>#ifndef VIENNAGRID_META_TYPELIST_HPP
#define VIENNAGRID_META_TYPELIST_HPP

#include "utils.hpp"

namespace viennagrid
{
  namespace meta
  {

    template <class head_, class tail_>
    struct typelist_t
    {
       typedef head_ head;
       typedef tail_ tail;
    };

//     C++11 version

//     template<typename ... types>
//     struct make_typelist;
//
//     template<>
//     struct make_typelist<>
//     {
//         typedef viennagrid::meta::null_type type;
//     };
//
//     template<typename head, typename ... tail>
//     struct make_typelist<head, tail...>
//     {
//         typedef viennagrid::meta::typelist_t<head, typename make_typelist<tail...>::type> type;
//     };

    template<   typename T01 = viennagrid::meta::null_type, typename T02 = viennagrid::meta::null_type, typename T03 = viennagrid::meta::null_type, typename T04 = viennagrid::meta::null_type,
                typename T05 = viennagrid::meta::null_type, typename T06 = viennagrid::meta::null_type, typename T07 = viennagrid::meta::null_type, typename T08 = viennagrid::meta::null_type,
                typename T09 = viennagrid::meta::null_type, typename T10 = viennagrid::meta::null_type, typename T11 = viennagrid::meta::null_type, typename T12 = viennagrid::meta::null_type,
                typename T13 = viennagrid::meta::null_type, typename T14 = viennagrid::meta::null_type, typename T15 = viennagrid::meta::null_type, typename T16 = viennagrid::meta::null_type,
                typename T17 = viennagrid::meta::null_type, typename T18 = viennagrid::meta::null_type, typename T19 = viennagrid::meta::null_type, typename T20 = viennagrid::meta::null_type >
    struct make_typelist
    {
        typedef
            typelist_t<
                T01,
                typename make_typelist<T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20>::type
            > type;
    };

    template<>
    struct make_typelist<
        viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type,
        viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type,
        viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type,
        viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type,
        viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type, viennagrid::meta::null_type>
    {
        typedef viennagrid::meta::null_type type;
    };

    namespace typelist
    {

        namespace result_of
        {

            // size of a typelist
            template <typename typelist> struct size;

            template <> struct size<null_type>
            {
                enum { value = 0 };
            };

            template <typename head, typename tail>
            struct size< typelist_t<head, tail> >
            {
                enum { value = 1 + size<tail>::value };
            };

            // index access
            template <typename typelist, unsigned int index> struct at
            {
                typedef out_of_range type;
            };

            template <typename head, typename tail>
            struct at<typelist_t<head, tail>, 0>
            {
                typedef head type;
            };

            template <typename head, typename tail, unsigned int i>
            struct at<typelist_t<head, tail>, i>
            {
                typedef typename at<tail, i - 1>::type type;
            };

            // returns the index of the first type in the typelist
            template <typename typelist, typename to_find> struct index_of;

            template <typename to_find>
            struct index_of<null_type, to_find>
            {
                enum { value = -1 };
            };

            template <typename to_find, typename tail>
            struct index_of<typelist_t<to_find, tail>, to_find>
            {
                enum { value = 0 };
            };

            template <typename head, typename tail, typename to_find>
            struct index_of<typelist_t<head, tail>, to_find>
            {
            private:
                enum { temp = index_of<tail, to_find>::value };
            public:
                enum { value = (temp == -1 ? -1 : 1 + temp) };
            };

            // push back a single type
            template <typename typelist, typename to_add> struct push_back;

            template <>
            struct push_back<null_type, null_type>
            {
                typedef null_type type;
            };

            template <typename to_add>
            struct push_back<null_type, to_add>
            {
                typedef typelist_t<to_add, null_type> type;
            };

            template <typename head, typename tail, typename to_add>
            struct push_back<typelist_t<head, tail>, to_add>
            {
                typedef typelist_t<head, typename push_back<tail, to_add>::type> type;
            };

            // push back list
            template <typename typelist, typename typelist_to_add> struct push_back_list;

            template <>
            struct push_back_list<null_type, null_type>
            {
                typedef null_type type;
            };

            template <typename head, typename tail>
            struct push_back_list<null_type, typelist_t<head, tail> >
            {
                typedef typelist_t<head, tail> type;
            };

            template <typename head, typename tail>
            struct push_back_list<typelist_t<head, tail>, null_type >
            {
                typedef typelist_t<head, tail> type;
            };

            template <typename head1, typename tail1, typename head2, typename tail2>
            struct push_back_list<typelist_t<head1, tail1>, typelist_t<head2, tail2> >
            {
                typedef typename push_back_list< typename push_back< typelist_t<head1, tail1>, head2>::type, tail2 >::type type;
            };

            // erase_at the type at index
            template <typename typelist, unsigned int index_to_erase> struct erase_at;

            template <unsigned int index_to_erase>
            struct erase_at<null_type, index_to_erase>
            {
                typedef null_type type;
            };

            template <typename head, typename tail>
            struct erase_at< typelist_t<head, tail>, 0>
            {
                typedef tail type;
            };

            template <typename head, typename tail, unsigned int index_to_erase>
            struct erase_at< typelist_t<head, tail>, index_to_erase>
            {
                typedef typelist_t<head, typename erase_at<tail, index_to_erase-1>::type> type;
            };

            // erase the first type
            template <typename typelist, typename to_erase> struct erase;

            template <typename to_erase>
            struct erase<null_type, to_erase>
            {
                typedef null_type type;
            };

            template <typename to_erase, typename tail>
            struct erase< typelist_t<to_erase, tail>, to_erase>
            {
                typedef tail type;
            };

            template <typename head, typename tail, typename to_erase>
            struct erase< typelist_t<head, tail>, to_erase>
            {
                typedef typelist_t<head, typename erase<tail, to_erase>::type> type;
            };

            // erase all types
            template <typename typelist, typename to_erase>
            struct erase_all;

            template <typename to_erase>
            struct erase_all<null_type, to_erase>
            {
                typedef null_type type;
            };

            template <typename to_erase, typename tail>
            struct erase_all< typelist_t<to_erase, tail>, to_erase>
            {
                // Go all the way down the list removing the type
                typedef typename erase_all<tail, to_erase>::type type;
            };
            template <typename head, typename tail, typename to_erase>

            struct erase_all< typelist_t<head, tail>, to_erase>
            {
                // Go all the way down the list removing the type
                typedef typelist_t<head, typename erase_all<tail, to_erase>::type> type;
            };

            // reverse
            template <typename typelist> struct reverse;

            template <> struct
            reverse<null_type>
            {
                typedef null_type type;
            };

            template <typename head, typename tail>
            struct reverse< typelist_t<head, tail> >
            {
            public:
                typedef typelist_t<head, tail> typelist;

                typedef typelist_t<
                    typename at<
                      typelist,
                      size<typelist>::value-1
                    >::type,
                    typename reverse<
                      typename erase_at<
                        typelist,
                        size<typelist>::value-1
                      >::type
                    >::type
                > type;
            };

            // no duplicate types
            template <typename typelist> struct no_duplicates;

            template <> struct
            no_duplicates<null_type>
            {
                typedef null_type type;
            };

            template <typename head, typename tail>
            struct no_duplicates< typelist_t<head, tail> >
            {
            private:
                typedef typename no_duplicates<tail>::type L1;
                typedef typename erase<L1, head>::type L2;
            public:
                typedef typelist_t<head, L2> type;
            };

            // replace the type at index by another type
            template <typename typelist, unsigned int index_to_replace, typename replaced> struct replace_at;

            template <unsigned int index_to_replace, typename replaced>
            struct replace_at<null_type, index_to_replace, replaced>
            {
                typedef null_type type;
            };

            template <typename head, typename tail, typename replaced>
            struct replace_at<typelist_t<head, tail>, 0, replaced>
            {
                typedef typelist_t<replaced, tail> type;
            };

            template <typename head, typename tail, unsigned int index_to_replace, typename replaced>
            struct replace_at<typelist_t<head, tail>, index_to_replace, replaced>
            {
                typedef typelist_t<head, typename replace_at<tail, index_to_replace-1, replaced>::type> type;
            };

            // replace the first type by another type
            template <typename typelist, typename to_replace, typename replaced> struct replace;

            template <typename to_replace, typename replaced>
            struct replace<null_type, to_replace, replaced>
            {
                typedef null_type type;
            };

            template <typename to_replace, typename tail, typename replaced>
            struct replace<typelist_t<to_replace, tail>, to_replace, replaced>
            {
                typedef typelist_t<replaced, tail> type;
            };

            template <typename head, typename tail, typename to_replace, typename replaced>
            struct replace<typelist_t<head, tail>, to_replace, replaced>
            {
                typedef typelist_t<head, typename replace<tail, to_replace, replaced>::type> type;
            };

            // replace all types by another type
            template <typename typelist, typename to_replace, typename replaced> struct replace_all;

            template <typename to_replace, typename replaced>
            struct replace_all<null_type, to_replace, replaced>
            {
                typedef null_type type;
            };

            template <typename to_replace, typename tail, typename replaced>
            struct replace_all<typelist_t<to_replace, tail>, to_replace, replaced>
            {
                typedef typelist_t<replaced, typename replace_all<tail, to_replace, replaced>::type> type;
            };

            template <typename head, typename tail, typename to_replace, typename replaced>
            struct replace_all<typelist_t<head, tail>, to_replace, replaced>
            {
                typedef typelist_t<head, typename replace_all<tail, to_replace, replaced>::type> type;
            };

            // returns only those types which are in both typelists
            template<typename typelist1, typename typelist2>
            struct intersection {};

           template<>
            struct intersection<null_type, null_type>
            {
                typedef null_type type;
            };

            template<typename head1, typename tail1>
            struct intersection<typelist_t<head1, tail1>, null_type>
            {
                typedef null_type type;
            };

            template<typename head2, typename tail2>
            struct intersection<null_type, typelist_t<head2, tail2> >
            {
                typedef null_type type;
            };

            template<typename head1, typename tail1, typename head2, typename tail2>
            struct intersection< typelist_t<head1, tail1>, typelist_t<head2, tail2> >
            {
                typedef typelist_t<head1, tail1> typelist1;
                typedef typelist_t<head2, tail2> typelist2;

                enum { search_result = index_of< typelist2, head1 >::value };

                typedef typename IF<
                    (search_result >= 0),
                    typename erase_at<typelist2, search_result>::type,
                    typelist2
                >::type new_typelist2;

                typedef typename IF<
                    (search_result >= 0),
                    typelist_t<head1, typename intersection<tail1, new_typelist2>::type >,
                    typename intersection<tail1, new_typelist2>::type
                >::type type;
            };

        }
    }
  } // namespace meta
} // namespace viennagrid

#endif // end file guardian
<|endoftext|>