src/Zone.cpp
author David Anderson <dvander@alliedmods.net>
Sun Nov 18 15:50:41 2012 -0800 (2012-11-18)
changeset 217 c22e983b3b6e
parent 209 5cbec15fadfe
child 222 0cde1379b29f
permissions -rw-r--r--
Get preinc working again.
     1 /* vim: set ts=4 sw=4 tw=99 et:
     2  *
     3  * Copyright (C) 2012 David Anderson
     4  *
     5  * This file is part of JITCraft.
     6  *
     7  * JITCraft is free software: you can redistribute it and/or modify it under
     8  * the terms of the GNU General Public License as published by the Free
     9  * Software Foundation, either version 3 of the License, or (at your option)
    10  * any later version.
    11  * 
    12  * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along with
    17  * JITCraft. If not, see http://www.gnu.org/licenses/.
    18  */
    19 #include <stdlib.h>
    20 #include "Zone.h"
    21 #include "StringPool.h"
    22 #include "TypeManager.h"
    23 #include "GlobalRoots.h"
    24 #include "AllocatorPolicies.h"
    25 #include "Array.h"
    26 #include "NativeTable.h"
    27 #include "Spaces-inl.h"
    28 #include "Heap-inl.h"
    29 
    30 using namespace ke;
    31 
    32 Zone *ke::SingleThreadedZone;
    33 
    34 void * const NullAddress::Sentinel = NULL;
    35 
    36 Zone::Zone()
    37   : stack_(thisFromCtor()),
    38     heap_(thisFromCtor()),
    39     types_(NULL),
    40     symbols_(NULL),
    41     globalRoots_(NULL),
    42     lastLocalRoot_(NULL),
    43     specialRoots_(NULL),
    44     hasPendingException_(false),
    45     reporter_(NULL)
    46 {
    47 }
    48 
    49 Zone::~Zone()
    50 {
    51     delete types_;
    52     delete nativeTable_;
    53     delete globalRoots_;
    54     delete symbols_;
    55 }
    56 
    57 bool
    58 Zone::initialize()
    59 {
    60     if (!stack_.initialize())
    61         return false;
    62     if (!heap_.initialize())
    63         return false;
    64 
    65     symbols_ = new StringPool(this);
    66     if (!symbols_ || !symbols_->initialize())
    67         return false;
    68 
    69     globalRoots_ = new GlobalRoots(this);
    70     if (!globalRoots_ || !globalRoots_->initialize())
    71         return false;
    72 
    73     nativeTable_ = new NativeTable(this);
    74     if (!nativeTable_ || !nativeTable_->initialize())
    75         return false;
    76 
    77     MapKind maps[] =
    78     {
    79         MapKind_Type,
    80         MapKind_ArrayType,
    81         MapKind_FunctionType,
    82         MapKind_StructType,
    83         MapKind_FixedArray,
    84         MapKind_ByteArray,
    85         MapKind_Code,
    86         MapKind_Reference,
    87         MapKind_MetaArray,
    88         MapKind_MetaStruct,
    89         MapKind_MetaEnvironment,
    90         MapKind_Module,
    91         MapKind_Function,
    92         MapKind_String,
    93         MapKind_Native,
    94         MapKind_Descriptor,
    95         MapKind_Box,
    96         MapKind_FreeRegion,
    97         MapKind_EnvironmentSlotDescriptorArray
    98     };
    99 
   100     maps_[MapKind_Meta] = heap_.metaMap();
   101     for (size_t i = 0; i < sizeof(maps) / sizeof(maps[0]); i++) {
   102         if ((maps_[maps[i]] = allocateMap(maps[i], sizeof(Map))) == NULL)
   103             return false;
   104     }
   105 
   106     types_ = new TypeManager(this);
   107     if (!types_ || !types_->initialize())
   108         return false;
   109 
   110     // Create the cached array maps for generic arrays. This is for the API
   111     // version of Invoke(), which needs to make arrays very quickly from C++.
   112     {
   113         // Generic "cell" array (contents do not matter, just non-gc things).
   114         Local<Type> type(this, types_->getPrimitive(PrimitiveType_Int32));
   115         if (!type)
   116             return false;
   117 
   118         type = types_->newExternalArray(type);
   119         if (!type)
   120             return false;
   121 
   122         // :TODO:
   123 #if 0
   124         externalGenericArrayMap_ = ArrayMap::Attach(this, type);
   125         if (!externalGenericArrayMap_)
   126             return false;
   127 #endif
   128 
   129         type = types_->getPrimitive(PrimitiveType_Char);
   130         if (!type)
   131             return false;
   132 
   133         type = types_->newExternalArray(type);
   134         if (!type)
   135             return false;
   136 
   137         // :TODO:
   138 #if 0
   139         externalCharArrayMap_ = ArrayMap::Attach(this, type);
   140         if (!externalCharArrayMap_)
   141             return false;
   142 #endif
   143     }
   144 
   145     return true;
   146 }
   147 
   148 Map *
   149 Zone::allocateMap(MapKind kind, size_t bytes, MapKind parent)
   150 {
   151     assert(maps_[parent]);
   152     Map *map = heap_.allocateMap(kind, bytes);
   153     if (!map)
   154         return NULL;
   155     map->init(maps_[parent]);
   156     return map;
   157 }
   158 
   159 void
   160 Zone::accept(VirtualObjectVisitor *visitor)
   161 {
   162     for (unsigned i = 0; i < MapKinds_Total; i++)
   163         visitor->visit(maps_[i].address());
   164     visitor->visit(externalCharArrayMap_.address());
   165     visitor->visit(externalGenericArrayMap_.address());
   166     types()->accept(visitor);
   167 
   168     Local<Object> *local = lastLocalRoot_;
   169     while (local) {
   170         visitor->visit(local->address());
   171         local = local->prev();
   172     }
   173 
   174     globalRoots_->accept(visitor);
   175     rootScopes_.accept(visitor);
   176     nativeTable_->accept(visitor);
   177 
   178     stack_.accept(visitor);
   179 }
   180 
   181 String *
   182 Zone::makeSymbol(const char *str, size_t length)
   183 {
   184     return symbols_->add(str, length);
   185 }
   186 
   187 String *
   188 Zone::makeSymbol(const char *str)
   189 {
   190     return makeSymbol(str, strlen(str));
   191 }
   192 
   193 bool
   194 Zone::hasPendingException()
   195 {
   196     return hasPendingException_;
   197 }
   198 
   199 void
   200 Zone::reportOutOfMemory()
   201 {
   202     
   203 }
   204 
   205 void
   206 Zone::reportError(Message message, ...)
   207 {
   208     va_list ap;
   209     va_start(ap, message);
   210     reportErrorVA(message, ap);
   211     va_end(ap);
   212 }
   213 
   214 #if defined(_MSC_VER)
   215 # define VA_COPY(to, from)  to = from
   216 #else
   217 # define VA_COPY(to, from)  va_copy(to, from)
   218 #endif
   219 
   220 static char *
   221 BuildErrorMessage(const char *format, va_list ap)
   222 {
   223     va_list use;
   224     VA_COPY(use, ap);
   225 
   226     // We over-allocate and zero terminate ahead of time, since LIBCRT's
   227     // version of vsnprintf is screwy.
   228     size_t size = 255;
   229     char *buffer = (char *)calloc(size + 1, 1);
   230     if (!buffer)
   231         return NULL;
   232 
   233     for (;;) {
   234         int r = vsnprintf(buffer, size, format, use);
   235 
   236         if (r > -1 && size_t(r) < size)
   237             return buffer;
   238        
   239 #if defined(_MSC_VER)
   240         if (r < 0)
   241             size *= 2;
   242 #else
   243         if (r > -1)
   244             size = size_t(r) + 1;
   245         else
   246             size *= 2;
   247 #endif
   248 
   249         free(buffer);
   250         if ((buffer = (char *)calloc(size + 1, 1)) == NULL)
   251             return NULL;
   252 
   253         VA_COPY(use, ap);
   254     }
   255 }
   256 
   257 void
   258 Zone::reportErrorVA(Message message, va_list ap)
   259 {
   260     char *report = BuildErrorMessage(Messages[message].format, ap);
   261     if (!report) {
   262         reportOutOfMemory();
   263         return;
   264     }
   265 
   266     if (reporter_) {
   267         // Reporters can re-enter. When we start having actual exception
   268         // objects that can be caught and inspected, this code will have to
   269         // save and restore the exception state.
   270         reporter_->onUncaughtException(report);
   271     }
   272 
   273     hasPendingException_ = true;
   274 
   275     free(report);
   276 }
   277 
   278 void
   279 Zone::beginCompilationErrors(const char *file)
   280 {
   281     if (reporter_)
   282         reporter_->beginCompilationErrors(file);
   283 }
   284 
   285 void
   286 Zone::reportCompilationError(Message message, unsigned line, unsigned col, va_list ap)
   287 {
   288     char *report = BuildErrorMessage(Messages[message].format, ap);
   289     if (!report) {
   290         reportOutOfMemory();
   291         return;
   292     }
   293 
   294     if (reporter_) {
   295         // Reporters can re-enter. When we start having actual exception
   296         // objects that can be caught and inspected, this code will have to
   297         // save and restore the exception state.
   298         reporter_->reportCompilationError(report, line, col);
   299     }
   300 
   301     free(report);
   302 }
   303 
   304 void
   305 Zone::endCompilationErrors()
   306 {
   307     if (reporter_)
   308         reporter_->endCompilationErrors();
   309 }
   310 
   311 void
   312 Zone::installErrorReporter(Ke::IMessageReporter *reporter)
   313 {
   314     reporter_ = reporter;
   315 }
   316 
   317 void
   318 ZoneAllocatorPolicy::reportOutOfMemory()
   319 {
   320     ZONE()->reportOutOfMemory();
   321 }
   322 
   323 void
   324 ZoneAllocatorPolicy::reportAllocationOverflow()
   325 {
   326     ZONE()->reportAllocationOverflow();
   327 }
   328 
   329 void
   330 Zone::reportAllocationOverflow()
   331 {
   332     reportError(Message_AllocationOverflow);
   333 }
   334 
   335 void
   336 Zone::clearPendingException()
   337 {
   338     hasPendingException_ = false;
   339 }
   340 
   341 void
   342 Zone::setPublicFunctionListener(Ke::IPublicFunctionListener *listener)
   343 {
   344     publicFunctionListener_ = listener;
   345 }
   346 
   347 AutoRooted::AutoRooted(Zone *zone)
   348   : zone_(zone),
   349     prev_(*zone->lastSpecialRoot())
   350 {
   351     *zone->lastSpecialRoot() = this;
   352 }
   353 
   354 AutoRooted::~AutoRooted()
   355 {
   356     *zone_->lastSpecialRoot() = prev_;
   357 }