src/Zone.cpp
author David Anderson <dvander@alliedmods.net>
Wed Dec 26 17:18:15 2012 -0800 (2012-12-26)
changeset 242 b7d14a8b918e
parent 240 e3c851a14f16
child 250 0998a43cc155
permissions -rw-r--r--
Fix typo.
     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_ReferenceType,
    84         MapKind_EnumType,
    85         MapKind_FixedArray,
    86         MapKind_ByteArray,
    87         MapKind_Code,
    88         MapKind_Reference,
    89         MapKind_MetaArray,
    90         MapKind_MetaStruct,
    91         MapKind_MetaEnvironment,
    92         MapKind_Module,
    93         MapKind_Function,
    94         MapKind_String,
    95         MapKind_Native,
    96         MapKind_Descriptor,
    97         MapKind_Box,
    98         MapKind_FreeRegion,
    99         MapKind_EnvironmentSlotDescriptorArray
   100     };
   101 
   102     maps_[MapKind_Meta] = heap_.metaMap();
   103     for (size_t i = 0; i < sizeof(maps) / sizeof(maps[0]); i++) {
   104         if ((maps_[maps[i]] = allocateMap(maps[i], sizeof(Map))) == NULL)
   105             return false;
   106     }
   107 
   108     types_ = new TypeManager(this);
   109     if (!types_ || !types_->initialize())
   110         return false;
   111 
   112     // Create the cached array maps for generic arrays. This is for the API
   113     // version of Invoke(), which needs to make arrays very quickly from C++.
   114     {
   115         // Generic "cell" array (contents do not matter, just non-gc things).
   116         Local<Type> type(this, types_->getPrimitive(PrimitiveType_Int32));
   117         if (!type)
   118             return false;
   119 
   120         type = types_->newExternalArray(type);
   121         if (!type)
   122             return false;
   123 
   124         // :TODO:
   125 #if 0
   126         externalGenericArrayMap_ = ArrayMap::Attach(this, type);
   127         if (!externalGenericArrayMap_)
   128             return false;
   129 #endif
   130 
   131         type = types_->getPrimitive(PrimitiveType_Char);
   132         if (!type)
   133             return false;
   134 
   135         type = types_->newExternalArray(type);
   136         if (!type)
   137             return false;
   138 
   139         // :TODO:
   140 #if 0
   141         externalCharArrayMap_ = ArrayMap::Attach(this, type);
   142         if (!externalCharArrayMap_)
   143             return false;
   144 #endif
   145     }
   146 
   147     return true;
   148 }
   149 
   150 Map *
   151 Zone::allocateMap(MapKind kind, size_t bytes, MapKind parent)
   152 {
   153     assert(maps_[parent]);
   154     Map *map = heap_.allocateMap(kind, bytes);
   155     if (!map)
   156         return NULL;
   157     map->init(maps_[parent]);
   158     return map;
   159 }
   160 
   161 void
   162 Zone::accept(VirtualObjectVisitor *visitor)
   163 {
   164     for (unsigned i = 0; i < MapKinds_Total; i++)
   165         visitor->visit(maps_[i].address());
   166     visitor->visit(externalCharArrayMap_.address());
   167     visitor->visit(externalGenericArrayMap_.address());
   168     types()->accept(visitor);
   169 
   170     Local<Object> *local = lastLocalRoot_;
   171     while (local) {
   172         visitor->visit(local->address());
   173         local = local->prev();
   174     }
   175 
   176     globalRoots_->accept(visitor);
   177     rootScopes_.accept(visitor);
   178     nativeTable_->accept(visitor);
   179 
   180     stack_.accept(visitor);
   181 }
   182 
   183 void
   184 Zone::sweepWeakRoots()
   185 {
   186     symbols_->sweep();
   187     types()->sweep();
   188 }
   189 
   190 String *
   191 Zone::makeSymbol(const char *str, size_t length)
   192 {
   193     return symbols_->add(str, length);
   194 }
   195 
   196 String *
   197 Zone::makeSymbol(const char *str)
   198 {
   199     return makeSymbol(str, strlen(str));
   200 }
   201 
   202 bool
   203 Zone::hasPendingException()
   204 {
   205     return hasPendingException_;
   206 }
   207 
   208 void
   209 Zone::reportOutOfMemory()
   210 {
   211     
   212 }
   213 
   214 void
   215 Zone::reportError(Message message, ...)
   216 {
   217     va_list ap;
   218     va_start(ap, message);
   219     reportErrorVA(message, ap);
   220     va_end(ap);
   221 }
   222 
   223 #if defined(_MSC_VER)
   224 # define VA_COPY(to, from)  to = from
   225 #else
   226 # define VA_COPY(to, from)  va_copy(to, from)
   227 #endif
   228 
   229 static char *
   230 BuildErrorMessage(const char *format, va_list ap)
   231 {
   232     va_list use;
   233     VA_COPY(use, ap);
   234 
   235     // We over-allocate and zero terminate ahead of time, since LIBCRT's
   236     // version of vsnprintf is screwy.
   237     size_t size = 255;
   238     char *buffer = (char *)calloc(size + 1, 1);
   239     if (!buffer)
   240         return NULL;
   241 
   242     for (;;) {
   243         int r = vsnprintf(buffer, size, format, use);
   244 
   245         if (r > -1 && size_t(r) < size)
   246             return buffer;
   247        
   248 #if defined(_MSC_VER)
   249         if (r < 0)
   250             size *= 2;
   251 #else
   252         if (r > -1)
   253             size = size_t(r) + 1;
   254         else
   255             size *= 2;
   256 #endif
   257 
   258         free(buffer);
   259         if ((buffer = (char *)calloc(size + 1, 1)) == NULL)
   260             return NULL;
   261 
   262         VA_COPY(use, ap);
   263     }
   264 }
   265 
   266 void
   267 Zone::reportErrorVA(Message message, va_list ap)
   268 {
   269     char *report = BuildErrorMessage(Messages[message].format, ap);
   270     if (!report) {
   271         reportOutOfMemory();
   272         return;
   273     }
   274 
   275     if (reporter_) {
   276         // Reporters can re-enter. When we start having actual exception
   277         // objects that can be caught and inspected, this code will have to
   278         // save and restore the exception state.
   279         reporter_->onUncaughtException(report);
   280     }
   281 
   282     hasPendingException_ = true;
   283 
   284     free(report);
   285 }
   286 
   287 void
   288 Zone::beginCompilationErrors(const char *file)
   289 {
   290     if (reporter_)
   291         reporter_->beginCompilationErrors(file);
   292 }
   293 
   294 void
   295 Zone::reportCompilationError(Message message, unsigned line, unsigned col, va_list ap)
   296 {
   297     char *report = BuildErrorMessage(Messages[message].format, ap);
   298     if (!report) {
   299         reportOutOfMemory();
   300         return;
   301     }
   302 
   303     if (reporter_) {
   304         // Reporters can re-enter. When we start having actual exception
   305         // objects that can be caught and inspected, this code will have to
   306         // save and restore the exception state.
   307         reporter_->reportCompilationError(report, line, col);
   308     }
   309 
   310     free(report);
   311 }
   312 
   313 void
   314 Zone::endCompilationErrors()
   315 {
   316     if (reporter_)
   317         reporter_->endCompilationErrors();
   318 }
   319 
   320 void
   321 Zone::installErrorReporter(Ke::IMessageReporter *reporter)
   322 {
   323     reporter_ = reporter;
   324 }
   325 
   326 void
   327 ZoneAllocatorPolicy::reportOutOfMemory()
   328 {
   329     ZONE()->reportOutOfMemory();
   330 }
   331 
   332 void
   333 ZoneAllocatorPolicy::reportAllocationOverflow()
   334 {
   335     ZONE()->reportAllocationOverflow();
   336 }
   337 
   338 void
   339 Zone::reportAllocationOverflow()
   340 {
   341     reportError(Message_AllocationOverflow);
   342 }
   343 
   344 void
   345 Zone::clearPendingException()
   346 {
   347     hasPendingException_ = false;
   348 }
   349 
   350 void
   351 Zone::setPublicFunctionListener(Ke::IPublicFunctionListener *listener)
   352 {
   353     publicFunctionListener_ = listener;
   354 }
   355 
   356 AutoRooted::AutoRooted(Zone *zone)
   357   : zone_(zone),
   358     prev_(*zone->lastSpecialRoot())
   359 {
   360     *zone->lastSpecialRoot() = this;
   361 }
   362 
   363 AutoRooted::~AutoRooted()
   364 {
   365     *zone_->lastSpecialRoot() = prev_;
   366 }