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