X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/b3378a02d0a811be38e530933fb9a57a3012a823..8a3643b285973c3e59ed19e5a8c83b137ea7c30c:/Pooling.hpp diff --git a/Pooling.hpp b/Pooling.hpp index 67b8a14..3af05ac 100644 --- a/Pooling.hpp +++ b/Pooling.hpp @@ -1,76 +1,228 @@ /* Cycript - Optimizing JavaScript Compiler/Runtime - * Copyright (C) 2009-2010 Jay Freeman (saurik) + * Copyright (C) 2009-2015 Jay Freeman (saurik) */ -/* GNU Lesser General Public License, Version 3 {{{ */ +/* GNU Affero General Public License, Version 3 {{{ */ /* - * Cycript is free software: you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Cycript 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 Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cycript. If not, see . + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 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 Affero General Public License for more details. + + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . **/ /* }}} */ -#ifndef CYPOOLING_HPP -#define CYPOOLING_HPP +#ifndef CYCRIPT_POOLING_HPP +#define CYCRIPT_POOLING_HPP -#include -#include +#include +#include +#include +#include + +#include + +#include #include "Exception.hpp" #include "Local.hpp" #include "Standard.hpp" -#include +// XXX: std::aligned_storage and alignof +static const size_t CYAlignment(sizeof(void *)); -_finline void *operator new(size_t size, apr_pool_t *pool) { - return apr_palloc(pool, size); +template +static void CYAlign(Type_ &data, size_t size) { + data = reinterpret_cast((reinterpret_cast(data) + (size - 1)) & ~static_cast(size - 1)); } -_finline void *operator new [](size_t size, apr_pool_t *pool) { - return apr_palloc(pool, size); -} +class CYPool; +_finline void *operator new(size_t size, CYPool &pool); +_finline void *operator new [](size_t size, CYPool &pool); class CYPool { private: - apr_pool_t *pool_; + uint8_t *data_; + size_t size_; + size_t next_; + + struct Cleaner { + Cleaner *next_; + void (*code_)(void *); + void *data_; + + Cleaner(Cleaner *next, void (*code)(void *), void *data) : + next_(next), + code_(code), + data_(data) + { + } + } *cleaner_; + + template + static void delete_(void *data) { + reinterpret_cast(data)->~Type_(); + } + + CYPool(const CYPool &); public: - CYPool(apr_pool_t *pool = NULL) { - _aprcall(apr_pool_create(&pool_, pool)); + CYPool(size_t next = 64) : + data_(NULL), + size_(0), + next_(next), + cleaner_(NULL) + { } ~CYPool() { - apr_pool_destroy(pool_); + for (Cleaner *cleaner(cleaner_); cleaner != NULL; ) { + Cleaner *next(cleaner->next_); + (*cleaner->code_)(cleaner->data_); + cleaner = next; + } + } + + template + Type_ *malloc(size_t size, size_t alignment = CYAlignment) { + uint8_t *end(data_); + CYAlign(end, alignment); + end += size; + + if (size_t(end - data_) > size_) { + size_t need(sizeof(Cleaner)); + CYAlign(need, alignment); + need += size; + size_ = std::max(next_, need); + next_ *= 2; + data_ = reinterpret_cast(::malloc(size_)); + atexit(free, data_); + _assert(size <= size_); + } + + uint8_t *data(data_); + CYAlign(data, alignment); + end = data + size; + size_ -= end - data_; + data_ = end; + return reinterpret_cast(data); + } + + char *strdup(const char *data) { + if (data == NULL) + return NULL; + return reinterpret_cast(memdup(data, strlen(data) + 1)); } - void Clear() { - apr_pool_clear(pool_); + template + Type_ *memdup(const Type_ *data, size_t size, size_t alignment = CYAlignment) { + Type_ *copy(malloc(size, alignment)); + memcpy(copy, data, size); + return copy; } - operator apr_pool_t *() const { - return pool_; + char *strndup(const char *data, size_t size) { + return strmemdup(data, strnlen(data, size)); } - char *operator ()(const char *data) const { - return apr_pstrdup(pool_, data); + char *strmemdup(const char *data, size_t size) { + char *copy(malloc(size + 1, 1)); + memcpy(copy, data, size); + copy[size] = '\0'; + return copy; } - char *operator ()(const char *data, size_t size) const { - return apr_pstrndup(pool_, data, size); + // XXX: this could be made much more efficient + __attribute__((__sentinel__)) + char *strcat(const char *data, ...) { + size_t size(strlen(data)); { + va_list args; + va_start(args, data); + + while (const char *arg = va_arg(args, const char *)) + size += strlen(arg); + + va_end(args); + } + + char *copy(malloc(size + 1, 1)); { + va_list args; + va_start(args, data); + + size_t offset(strlen(data)); + memcpy(copy, data, offset); + + while (const char *arg = va_arg(args, const char *)) { + size_t size(strlen(arg)); + memcpy(copy + offset, arg, size); + offset += size; + } + + va_end(args); + } + + copy[size] = '\0'; + return copy; + } + + // XXX: most people using this might should use sprintf + char *itoa(long value) { + return sprintf(16, "%ld", value); + } + + __attribute__((__format__(__printf__, 3, 4))) + char *sprintf(size_t size, const char *format, ...) { + va_list args; + va_start(args, format); + char *copy(vsprintf(size, format, args)); + va_end(args); + return copy; + } + + char *vsprintf(size_t size, const char *format, va_list args) { + va_list copy; + va_copy(copy, args); + char buffer[size]; + int writ(vsnprintf(buffer, size, format, copy)); + va_end(copy); + _assert(writ >= 0); + + if (size_t(writ) >= size) + return vsprintf(writ + 1, format, args); + return strmemdup(buffer, writ); + } + + void atexit(void (*code)(void *), void *data = NULL); + + template + Type_ &object() { + Type_ *value(new(*this) Type_()); + atexit(&delete_, value); + return *value; } }; +_finline void *operator new(size_t size, CYPool &pool) { + return pool.malloc(size); +} + +_finline void *operator new [](size_t size, CYPool &pool) { + return pool.malloc(size); +} + +_finline void CYPool::atexit(void (*code)(void *), void *data) { + cleaner_ = new(*this) Cleaner(cleaner_, code, data); +} + struct CYData { - apr_pool_t *pool_; + CYPool *pool_; unsigned count_; CYData() : @@ -78,29 +230,33 @@ struct CYData { { } + CYData(CYPool &pool) : + pool_(&pool), + count_(_not(unsigned)) + { + } + virtual ~CYData() { } - static void *operator new(size_t size, apr_pool_t *pool) { - void *data(apr_palloc(pool, size)); - reinterpret_cast(data)->pool_ = pool; + static void *operator new(size_t size, CYPool &pool) { + void *data(pool.malloc(size)); + reinterpret_cast(data)->pool_ = &pool; return data; } static void *operator new(size_t size) { - apr_pool_t *pool; - _aprcall(apr_pool_create(&pool, NULL)); - return operator new(size, pool); + return operator new(size, *new CYPool()); } static void operator delete(void *data) { - apr_pool_destroy(reinterpret_cast(data)->pool_); + delete reinterpret_cast(data)->pool_; } }; template struct CYPoolAllocator { - apr_pool_t *pool_; + CYPool *pool_; typedef Type_ value_type; typedef value_type *pointer; @@ -122,7 +278,7 @@ struct CYPoolAllocator { } pointer allocate(size_type size, const void *hint = 0) { - return reinterpret_cast(apr_palloc(pool_, size)); + return pool_->malloc(size); } void deallocate(pointer data, size_type size) { @@ -156,17 +312,20 @@ class CYLocalPool : public CYPool { private: - CYLocal local_; + CYLocal local_; public: CYLocalPool() : CYPool(), - local_(operator apr_pool_t *()) + local_(this) { } }; #define $pool \ - CYLocal::Get() + (*CYLocal::Get()) + +template <> +::pthread_key_t CYLocal::key_; -#endif/*CYPOOLING_HPP*/ +#endif/*CYCRIPT_POOLING_HPP*/