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