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