diff -r c4b1341297e5 -r ba85a47ee414 src/Zone.cpp --- a/src/Zone.cpp Mon Jun 10 00:46:29 2013 +0100 +++ b/src/Zone.cpp Mon Jun 10 01:04:43 2013 +0100 @@ -1,368 +1,368 @@ -/* vim: set ts=4 sw=4 tw=99 et: - * - * Copyright (C) 2012 David Anderson - * - * This file is part of JITCraft. - * - * JITCraft is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * Foobar 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 - * JITCraft. If not, see http://www.gnu.org/licenses/. - */ -#include -#include "Zone.h" -#include "StringPool.h" -#include "TypeManager.h" -#include "GlobalRoots.h" -#include "AllocatorPolicies.h" -#include "Array.h" -#include "NativeTable.h" -#include "Packages.h" -#include "Spaces-inl.h" -#include "Heap-inl.h" - -using namespace ke; - -Zone *ke::SingleThreadedZone; - -void * const NullAddress::Sentinel = NULL; - -Zone::Zone() - : stack_(thisFromCtor()), - heap_(thisFromCtor()), - types_(NULL), - symbols_(NULL), - globalRoots_(NULL), - nativeTable_(NULL), - packages_(NULL), - lastLocalRoot_(NULL), - specialRoots_(NULL), - hasPendingException_(false), - reporter_(NULL) -{ -} - -Zone::~Zone() -{ - delete nativeTable_; - delete types_; - delete symbols_; - delete packages_; - delete globalRoots_; -} - -bool -Zone::initialize() -{ - if (!stack_.initialize()) - return false; - if (!heap_.initialize()) - return false; - - symbols_ = new StringPool(this); - if (!symbols_ || !symbols_->initialize()) - return false; - - globalRoots_ = new GlobalRoots(this); - if (!globalRoots_ || !globalRoots_->initialize()) - return false; - - nativeTable_ = new NativeTable(this); - if (!nativeTable_ || !nativeTable_->initialize()) - return false; - - packages_ = new PackageCache(this); - if (!packages_ || !packages_->initialize()) - return false; - - MapKind maps[] = - { - MapKind_Type, - MapKind_ArrayType, - MapKind_FunctionType, - MapKind_StructType, - MapKind_ReferenceType, - MapKind_EnumType, - MapKind_FixedArray, - MapKind_ByteArray, - MapKind_Code, - MapKind_Reference, - MapKind_MetaArray, - MapKind_MetaStruct, - MapKind_MetaEnvironment, - MapKind_Module, - MapKind_Function, - MapKind_String, - MapKind_Native, - MapKind_Descriptor, - MapKind_Box, - MapKind_List, - MapKind_Package, - MapKind_FreeRegion, - MapKind_EnvironmentSlotDescriptorArray - }; - - maps_[MapKind_Meta] = heap_.metaMap(); - for (size_t i = 0; i < sizeof(maps) / sizeof(maps[0]); i++) { - if ((maps_[maps[i]] = allocateMap(maps[i], sizeof(Map))) == NULL) - return false; - } - - types_ = new TypeManager(this); - if (!types_ || !types_->initialize()) - return false; - - // Create the cached array maps for generic arrays. This is for the API - // version of Invoke(), which needs to make arrays very quickly from C++. - { - // Generic "cell" array (contents do not matter, just non-gc things). - Local type(this, types_->getPrimitive(PrimitiveType_Int32)); - if (!type) - return false; - - type = types_->newExternalArray(type); - if (!type) - return false; - - // :TODO: -#if 0 - externalGenericArrayMap_ = ArrayMap::Attach(this, type); - if (!externalGenericArrayMap_) - return false; -#endif - - type = types_->getPrimitive(PrimitiveType_Char); - if (!type) - return false; - - type = types_->newExternalArray(type); - if (!type) - return false; - - // :TODO: -#if 0 - externalCharArrayMap_ = ArrayMap::Attach(this, type); - if (!externalCharArrayMap_) - return false; -#endif - } - - return true; -} - -Map * -Zone::allocateMap(MapKind kind, size_t bytes, MapKind parent) -{ - assert(maps_[parent]); - Map *map = heap_.allocateMap(kind, bytes); - if (!map) - return NULL; - map->init(maps_[parent]); - return map; -} - -void -Zone::accept(VirtualObjectVisitor *visitor) -{ - for (unsigned i = 0; i < MapKinds_Total; i++) - visitor->visit(maps_[i].address()); - visitor->visit(externalCharArrayMap_.address()); - visitor->visit(externalGenericArrayMap_.address()); - types()->accept(visitor); - - Local *local = lastLocalRoot_; - while (local) { - visitor->visit(local->address()); - local = local->prev(); - } - - globalRoots_->accept(visitor); - rootScopes_.accept(visitor); - nativeTable_->accept(visitor); - packages_->accept(visitor); - - stack_.accept(visitor); -} - -void -Zone::sweepWeakRoots() -{ - symbols_->sweep(); - types()->sweep(); -} - -String * -Zone::makeSymbol(const char *str, size_t length) -{ - return symbols_->add(str, length); -} - -String * -Zone::makeSymbol(const char *str) -{ - return makeSymbol(str, strlen(str)); -} - -bool -Zone::hasPendingException() -{ - return hasPendingException_; -} - -void -Zone::reportOutOfMemory() -{ - -} - -void -Zone::reportError(Message message, ...) -{ - va_list ap; - va_start(ap, message); - reportErrorVA(message, ap); - va_end(ap); -} - -#if defined(_MSC_VER) -# define VA_COPY(to, from) to = from -#else -# define VA_COPY(to, from) va_copy(to, from) -#endif - -char * -ke::BuildErrorMessage(const char *format, va_list ap) -{ - va_list use; - VA_COPY(use, ap); - - // We over-allocate and zero terminate ahead of time, since LIBCRT's - // version of vsnprintf is screwy. - size_t size = 255; - char *buffer = (char *)calloc(size + 1, 1); - if (!buffer) - return NULL; - - for (;;) { - int r = vsnprintf(buffer, size, format, use); - - if (r > -1 && size_t(r) < size) - return buffer; - -#if defined(_MSC_VER) - if (r < 0) - size *= 2; -#else - if (r > -1) - size = size_t(r) + 1; - else - size *= 2; -#endif - - free(buffer); - if ((buffer = (char *)calloc(size + 1, 1)) == NULL) - return NULL; - - VA_COPY(use, ap); - } -} - -void -ke::FreeErrorMessage(const char *message) -{ - free((void *)message); -} - -void -Zone::reportErrorVA(Message message, va_list ap) -{ - char *report = BuildErrorMessage(Messages[message].format, ap); - if (!report) { - reportOutOfMemory(); - return; - } - - if (reporter_) { - // Reporters can re-enter. When we start having actual exception - // objects that can be caught and inspected, this code will have to - // save and restore the exception state. - reporter_->onUncaughtException(report); - } - - hasPendingException_ = true; - - FreeErrorMessage(report); -} - -void -Zone::installErrorReporter(Ke::IMessageReporter *reporter) -{ - reporter_ = reporter; -} - -void -ZoneAllocatorPolicy::reportOutOfMemory() -{ - ZONE()->reportOutOfMemory(); -} - -void -ZoneAllocatorPolicy::reportAllocationOverflow() -{ - ZONE()->reportAllocationOverflow(); -} - -void -Zone::reportAllocationOverflow() -{ - reportError(Message_AllocationOverflow); -} - -void -Zone::clearPendingException() -{ - hasPendingException_ = false; -} - -void -Zone::setPublicFunctionListener(Ke::IPublicFunctionListener *listener) -{ - publicFunctionListener_ = listener; -} - -void * -Zone::malloc(size_t size) -{ - void *ptr = ::malloc(size); - if (!ptr) - reportOutOfMemory(); - return ptr; -} - -void * -Zone::realloc(void *ptr, size_t size) -{ - ptr = ::realloc(ptr, size); - if (!ptr) - reportOutOfMemory(); - return ptr; -} - -AutoRooted::AutoRooted(Zone *zone) - : zone_(zone), - prev_(*zone->lastSpecialRoot()) -{ - *zone->lastSpecialRoot() = this; -} - -AutoRooted::~AutoRooted() -{ - *zone_->lastSpecialRoot() = prev_; -} +/* vim: set ts=4 sw=4 tw=99 et: + * + * Copyright (C) 2012 David Anderson + * + * This file is part of JITCraft. + * + * JITCraft is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * Foobar 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 + * JITCraft. If not, see http://www.gnu.org/licenses/. + */ +#include +#include "Zone.h" +#include "StringPool.h" +#include "TypeManager.h" +#include "GlobalRoots.h" +#include "AllocatorPolicies.h" +#include "Array.h" +#include "NativeTable.h" +#include "Packages.h" +#include "Spaces-inl.h" +#include "Heap-inl.h" + +using namespace ke; + +Zone *ke::SingleThreadedZone; + +void * const NullAddress::Sentinel = NULL; + +Zone::Zone() + : stack_(thisFromCtor()), + heap_(thisFromCtor()), + types_(NULL), + symbols_(NULL), + globalRoots_(NULL), + nativeTable_(NULL), + packages_(NULL), + lastLocalRoot_(NULL), + specialRoots_(NULL), + hasPendingException_(false), + reporter_(NULL) +{ +} + +Zone::~Zone() +{ + delete nativeTable_; + delete types_; + delete symbols_; + delete packages_; + delete globalRoots_; +} + +bool +Zone::initialize() +{ + if (!stack_.initialize()) + return false; + if (!heap_.initialize()) + return false; + + symbols_ = new StringPool(this); + if (!symbols_ || !symbols_->initialize()) + return false; + + globalRoots_ = new GlobalRoots(this); + if (!globalRoots_ || !globalRoots_->initialize()) + return false; + + nativeTable_ = new NativeTable(this); + if (!nativeTable_ || !nativeTable_->initialize()) + return false; + + packages_ = new PackageCache(this); + if (!packages_ || !packages_->initialize()) + return false; + + MapKind maps[] = + { + MapKind_Type, + MapKind_ArrayType, + MapKind_FunctionType, + MapKind_StructType, + MapKind_ReferenceType, + MapKind_EnumType, + MapKind_FixedArray, + MapKind_ByteArray, + MapKind_Code, + MapKind_Reference, + MapKind_MetaArray, + MapKind_MetaStruct, + MapKind_MetaEnvironment, + MapKind_Module, + MapKind_Function, + MapKind_String, + MapKind_Native, + MapKind_Descriptor, + MapKind_Box, + MapKind_List, + MapKind_Package, + MapKind_FreeRegion, + MapKind_EnvironmentSlotDescriptorArray + }; + + maps_[MapKind_Meta] = heap_.metaMap(); + for (size_t i = 0; i < sizeof(maps) / sizeof(maps[0]); i++) { + if ((maps_[maps[i]] = allocateMap(maps[i], sizeof(Map))) == NULL) + return false; + } + + types_ = new TypeManager(this); + if (!types_ || !types_->initialize()) + return false; + + // Create the cached array maps for generic arrays. This is for the API + // version of Invoke(), which needs to make arrays very quickly from C++. + { + // Generic "cell" array (contents do not matter, just non-gc things). + Local type(this, types_->getPrimitive(PrimitiveType_Int32)); + if (!type) + return false; + + type = types_->newExternalArray(type); + if (!type) + return false; + + // :TODO: +#if 0 + externalGenericArrayMap_ = ArrayMap::Attach(this, type); + if (!externalGenericArrayMap_) + return false; +#endif + + type = types_->getPrimitive(PrimitiveType_Char); + if (!type) + return false; + + type = types_->newExternalArray(type); + if (!type) + return false; + + // :TODO: +#if 0 + externalCharArrayMap_ = ArrayMap::Attach(this, type); + if (!externalCharArrayMap_) + return false; +#endif + } + + return true; +} + +Map * +Zone::allocateMap(MapKind kind, size_t bytes, MapKind parent) +{ + assert(maps_[parent]); + Map *map = heap_.allocateMap(kind, bytes); + if (!map) + return NULL; + map->init(maps_[parent]); + return map; +} + +void +Zone::accept(VirtualObjectVisitor *visitor) +{ + for (unsigned i = 0; i < MapKinds_Total; i++) + visitor->visit(maps_[i].address()); + visitor->visit(externalCharArrayMap_.address()); + visitor->visit(externalGenericArrayMap_.address()); + types()->accept(visitor); + + Local *local = lastLocalRoot_; + while (local) { + visitor->visit(local->address()); + local = local->prev(); + } + + globalRoots_->accept(visitor); + rootScopes_.accept(visitor); + nativeTable_->accept(visitor); + packages_->accept(visitor); + + stack_.accept(visitor); +} + +void +Zone::sweepWeakRoots() +{ + symbols_->sweep(); + types()->sweep(); +} + +String * +Zone::makeSymbol(const char *str, size_t length) +{ + return symbols_->add(str, length); +} + +String * +Zone::makeSymbol(const char *str) +{ + return makeSymbol(str, strlen(str)); +} + +bool +Zone::hasPendingException() +{ + return hasPendingException_; +} + +void +Zone::reportOutOfMemory() +{ + +} + +void +Zone::reportError(Message message, ...) +{ + va_list ap; + va_start(ap, message); + reportErrorVA(message, ap); + va_end(ap); +} + +#if defined(_MSC_VER) +# define VA_COPY(to, from) to = from +#else +# define VA_COPY(to, from) va_copy(to, from) +#endif + +char * +ke::BuildErrorMessage(const char *format, va_list ap) +{ + va_list use; + VA_COPY(use, ap); + + // We over-allocate and zero terminate ahead of time, since LIBCRT's + // version of vsnprintf is screwy. + size_t size = 255; + char *buffer = (char *)calloc(size + 1, 1); + if (!buffer) + return NULL; + + for (;;) { + int r = vsnprintf(buffer, size, format, use); + + if (r > -1 && size_t(r) < size) + return buffer; + +#if defined(_MSC_VER) + if (r < 0) + size *= 2; +#else + if (r > -1) + size = size_t(r) + 1; + else + size *= 2; +#endif + + free(buffer); + if ((buffer = (char *)calloc(size + 1, 1)) == NULL) + return NULL; + + VA_COPY(use, ap); + } +} + +void +ke::FreeErrorMessage(const char *message) +{ + free((void *)message); +} + +void +Zone::reportErrorVA(Message message, va_list ap) +{ + char *report = BuildErrorMessage(Messages[message].format, ap); + if (!report) { + reportOutOfMemory(); + return; + } + + if (reporter_) { + // Reporters can re-enter. When we start having actual exception + // objects that can be caught and inspected, this code will have to + // save and restore the exception state. + reporter_->onUncaughtException(report); + } + + hasPendingException_ = true; + + FreeErrorMessage(report); +} + +void +Zone::installErrorReporter(Ke::IMessageReporter *reporter) +{ + reporter_ = reporter; +} + +void +ZoneAllocatorPolicy::reportOutOfMemory() +{ + ZONE()->reportOutOfMemory(); +} + +void +ZoneAllocatorPolicy::reportAllocationOverflow() +{ + ZONE()->reportAllocationOverflow(); +} + +void +Zone::reportAllocationOverflow() +{ + reportError(Message_AllocationOverflow); +} + +void +Zone::clearPendingException() +{ + hasPendingException_ = false; +} + +void +Zone::setPublicFunctionListener(Ke::IPublicFunctionListener *listener) +{ + publicFunctionListener_ = listener; +} + +void * +Zone::malloc(size_t size) +{ + void *ptr = ::malloc(size); + if (!ptr) + reportOutOfMemory(); + return ptr; +} + +void * +Zone::realloc(void *ptr, size_t size) +{ + ptr = ::realloc(ptr, size); + if (!ptr) + reportOutOfMemory(); + return ptr; +} + +AutoRooted::AutoRooted(Zone *zone) + : zone_(zone), + prev_(*zone->lastSpecialRoot()) +{ + *zone->lastSpecialRoot() = this; +} + +AutoRooted::~AutoRooted() +{ + *zone_->lastSpecialRoot() = prev_; +}