src/Zone.cpp
author Asher Baker <asherkin@gmail.com>
Mon Jun 10 15:52:44 2013 +0100 (2013-06-10)
changeset 265 3a903b89a514
parent 263 ba85a47ee414
permissions -rw-r--r--
Fixed type checking for multidimensional arrays.
     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 "Packages.h"
    28 #include "Spaces-inl.h"
    29 #include "Heap-inl.h"
    30 
    31 using namespace ke;
    32 
    33 Zone *ke::SingleThreadedZone;
    34 
    35 void * const NullAddress::Sentinel = NULL;
    36 
    37 Zone::Zone()
    38   : stack_(thisFromCtor()),
    39     heap_(thisFromCtor()),
    40     types_(NULL),
    41     symbols_(NULL),
    42     globalRoots_(NULL),
    43     nativeTable_(NULL),
    44     packages_(NULL),
    45     lastLocalRoot_(NULL),
    46     specialRoots_(NULL),
    47     hasPendingException_(false),
    48     reporter_(NULL)
    49 {
    50 }
    51 
    52 Zone::~Zone()
    53 {
    54     delete nativeTable_;
    55     delete types_;
    56     delete symbols_;
    57     delete packages_;
    58     delete globalRoots_;
    59 }
    60 
    61 bool
    62 Zone::initialize()
    63 {
    64     if (!stack_.initialize())
    65         return false;
    66     if (!heap_.initialize())
    67         return false;
    68 
    69     symbols_ = new StringPool(this);
    70     if (!symbols_ || !symbols_->initialize())
    71         return false;
    72 
    73     globalRoots_ = new GlobalRoots(this);
    74     if (!globalRoots_ || !globalRoots_->initialize())
    75         return false;
    76 
    77     nativeTable_ = new NativeTable(this);
    78     if (!nativeTable_ || !nativeTable_->initialize())
    79         return false;
    80 
    81     packages_ = new PackageCache(this);
    82     if (!packages_ || !packages_->initialize())
    83         return false;
    84 
    85     MapKind maps[] =
    86     {
    87         MapKind_Type,
    88         MapKind_ArrayType,
    89         MapKind_FunctionType,
    90         MapKind_StructType,
    91         MapKind_ReferenceType,
    92         MapKind_EnumType,
    93         MapKind_FixedArray,
    94         MapKind_ByteArray,
    95         MapKind_Code,
    96         MapKind_Reference,
    97         MapKind_MetaArray,
    98         MapKind_MetaStruct,
    99         MapKind_MetaEnvironment,
   100         MapKind_Module,
   101         MapKind_Function,
   102         MapKind_String,
   103         MapKind_Native,
   104         MapKind_Descriptor,
   105         MapKind_Box,
   106         MapKind_List,
   107         MapKind_Package,
   108         MapKind_FreeRegion,
   109         MapKind_EnvironmentSlotDescriptorArray
   110     };
   111 
   112     maps_[MapKind_Meta] = heap_.metaMap();
   113     for (size_t i = 0; i < sizeof(maps) / sizeof(maps[0]); i++) {
   114         if ((maps_[maps[i]] = allocateMap(maps[i], sizeof(Map))) == NULL)
   115             return false;
   116     }
   117 
   118     types_ = new TypeManager(this);
   119     if (!types_ || !types_->initialize())
   120         return false;
   121 
   122     // Create the cached array maps for generic arrays. This is for the API
   123     // version of Invoke(), which needs to make arrays very quickly from C++.
   124     {
   125         // Generic "cell" array (contents do not matter, just non-gc things).
   126         Local<Type> type(this, types_->getPrimitive(PrimitiveType_Int32));
   127         if (!type)
   128             return false;
   129 
   130         type = types_->newExternalArray(type);
   131         if (!type)
   132             return false;
   133 
   134         // :TODO:
   135 #if 0
   136         externalGenericArrayMap_ = ArrayMap::Attach(this, type);
   137         if (!externalGenericArrayMap_)
   138             return false;
   139 #endif
   140 
   141         type = types_->getPrimitive(PrimitiveType_Char);
   142         if (!type)
   143             return false;
   144 
   145         type = types_->newExternalArray(type);
   146         if (!type)
   147             return false;
   148 
   149         // :TODO:
   150 #if 0
   151         externalCharArrayMap_ = ArrayMap::Attach(this, type);
   152         if (!externalCharArrayMap_)
   153             return false;
   154 #endif
   155     }
   156 
   157     return true;
   158 }
   159 
   160 Map *
   161 Zone::allocateMap(MapKind kind, size_t bytes, MapKind parent)
   162 {
   163     assert(maps_[parent]);
   164     Map *map = heap_.allocateMap(kind, bytes);
   165     if (!map)
   166         return NULL;
   167     map->init(maps_[parent]);
   168     return map;
   169 }
   170 
   171 void
   172 Zone::accept(VirtualObjectVisitor *visitor)
   173 {
   174     for (unsigned i = 0; i < MapKinds_Total; i++)
   175         visitor->visit(maps_[i].address());
   176     visitor->visit(externalCharArrayMap_.address());
   177     visitor->visit(externalGenericArrayMap_.address());
   178     types()->accept(visitor);
   179 
   180     Local<Object> *local = lastLocalRoot_;
   181     while (local) {
   182         visitor->visit(local->address());
   183         local = local->prev();
   184     }
   185 
   186     globalRoots_->accept(visitor);
   187     rootScopes_.accept(visitor);
   188     nativeTable_->accept(visitor);
   189     packages_->accept(visitor);
   190 
   191     stack_.accept(visitor);
   192 }
   193 
   194 void
   195 Zone::sweepWeakRoots()
   196 {
   197     symbols_->sweep();
   198     types()->sweep();
   199 }
   200 
   201 String *
   202 Zone::makeSymbol(const char *str, size_t length)
   203 {
   204     return symbols_->add(str, length);
   205 }
   206 
   207 String *
   208 Zone::makeSymbol(const char *str)
   209 {
   210     return makeSymbol(str, strlen(str));
   211 }
   212 
   213 bool
   214 Zone::hasPendingException()
   215 {
   216     return hasPendingException_;
   217 }
   218 
   219 void
   220 Zone::reportOutOfMemory()
   221 {
   222     
   223 }
   224 
   225 void
   226 Zone::reportError(Message message, ...)
   227 {
   228     va_list ap;
   229     va_start(ap, message);
   230     reportErrorVA(message, ap);
   231     va_end(ap);
   232 }
   233 
   234 #if defined(_MSC_VER)
   235 # define VA_COPY(to, from)  to = from
   236 #else
   237 # define VA_COPY(to, from)  va_copy(to, from)
   238 #endif
   239 
   240 char *
   241 ke::BuildErrorMessage(const char *format, va_list ap)
   242 {
   243     va_list use;
   244     VA_COPY(use, ap);
   245 
   246     // We over-allocate and zero terminate ahead of time, since LIBCRT's
   247     // version of vsnprintf is screwy.
   248     size_t size = 255;
   249     char *buffer = (char *)calloc(size + 1, 1);
   250     if (!buffer)
   251         return NULL;
   252 
   253     for (;;) {
   254         int r = vsnprintf(buffer, size, format, use);
   255 
   256         if (r > -1 && size_t(r) < size)
   257             return buffer;
   258        
   259 #if defined(_MSC_VER)
   260         if (r < 0)
   261             size *= 2;
   262 #else
   263         if (r > -1)
   264             size = size_t(r) + 1;
   265         else
   266             size *= 2;
   267 #endif
   268 
   269         free(buffer);
   270         if ((buffer = (char *)calloc(size + 1, 1)) == NULL)
   271             return NULL;
   272 
   273         VA_COPY(use, ap);
   274     }
   275 }
   276 
   277 void
   278 ke::FreeErrorMessage(const char *message)
   279 {
   280     free((void *)message);
   281 }
   282 
   283 void
   284 Zone::reportErrorVA(Message message, va_list ap)
   285 {
   286     char *report = BuildErrorMessage(Messages[message].format, ap);
   287     if (!report) {
   288         reportOutOfMemory();
   289         return;
   290     }
   291 
   292     if (reporter_) {
   293         // Reporters can re-enter. When we start having actual exception
   294         // objects that can be caught and inspected, this code will have to
   295         // save and restore the exception state.
   296         reporter_->onUncaughtException(report);
   297     }
   298 
   299     hasPendingException_ = true;
   300 
   301     FreeErrorMessage(report);
   302 }
   303 
   304 void
   305 Zone::installErrorReporter(Ke::IMessageReporter *reporter)
   306 {
   307     reporter_ = reporter;
   308 }
   309 
   310 void
   311 ZoneAllocatorPolicy::reportOutOfMemory()
   312 {
   313     ZONE()->reportOutOfMemory();
   314 }
   315 
   316 void
   317 ZoneAllocatorPolicy::reportAllocationOverflow()
   318 {
   319     ZONE()->reportAllocationOverflow();
   320 }
   321 
   322 void
   323 Zone::reportAllocationOverflow()
   324 {
   325     reportError(Message_AllocationOverflow);
   326 }
   327 
   328 void
   329 Zone::clearPendingException()
   330 {
   331     hasPendingException_ = false;
   332 }
   333 
   334 void
   335 Zone::setPublicFunctionListener(Ke::IPublicFunctionListener *listener)
   336 {
   337     publicFunctionListener_ = listener;
   338 }
   339 
   340 void *
   341 Zone::malloc(size_t size)
   342 {
   343     void *ptr = ::malloc(size);
   344     if (!ptr)
   345         reportOutOfMemory();
   346     return ptr;
   347 }
   348 
   349 void *
   350 Zone::realloc(void *ptr, size_t size)
   351 {
   352     ptr = ::realloc(ptr, size);
   353     if (!ptr)
   354         reportOutOfMemory();
   355     return ptr;
   356 }
   357 
   358 AutoRooted::AutoRooted(Zone *zone)
   359   : zone_(zone),
   360     prev_(*zone->lastSpecialRoot())
   361 {
   362     *zone->lastSpecialRoot() = this;
   363 }
   364 
   365 AutoRooted::~AutoRooted()
   366 {
   367     *zone_->lastSpecialRoot() = prev_;
   368 }