jitcraft/Zone.cpp
author David Anderson <dvander@alliedmods.net>
Mon Jul 23 01:19:44 2012 -0700 (2012-07-23)
changeset 85 06a0015b6a5c
parent 69 dfce0539a77d
permissions -rw-r--r--
Added global variable support.
     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 
    27 using namespace ke;
    28 
    29 Zone *ke::SingleThreadedZone;
    30 
    31 Zone::Zone()
    32   : stack_(thisFromCtor()),
    33     heap_(thisFromCtor()),
    34     types_(NULL),
    35     symbols_(NULL),
    36     globalRoots_(NULL),
    37     lastLocalRoot_(NULL),
    38     hasPendingException_(false),
    39     reporter_(NULL)
    40 {
    41 }
    42 
    43 Zone::~Zone()
    44 {
    45     delete types_;
    46     delete symbols_;
    47     delete globalRoots_;
    48 }
    49 
    50 bool
    51 Zone::initialize()
    52 {
    53     if (!stack_.initialize())
    54         return false;
    55     if (!heap_.initialize())
    56         return false;
    57 
    58     symbols_ = new StringPool(this);
    59     if (!symbols_ || !symbols_->initialize())
    60         return false;
    61 
    62     globalRoots_ = new GlobalRoots(this);
    63     if (!globalRoots_ || !globalRoots_->initialize())
    64         return false;
    65 
    66     maps_[MapKind_Meta] = heap_.metaMap();
    67     if ((maps_[MapKind_Type] = allocateMap(MapKind_Type, sizeof(Map))) == NULL)
    68         return false;
    69     if ((maps_[MapKind_FixedArray] = allocateMap(MapKind_FixedArray, sizeof(Map))) == NULL)
    70         return false;
    71     if ((maps_[MapKind_ByteArray] = allocateMap(MapKind_ByteArray, sizeof(Map))) == NULL)
    72         return false;
    73     if ((maps_[MapKind_Code] = allocateMap(MapKind_Code, sizeof(Map))) == NULL)
    74         return false;
    75     if ((maps_[MapKind_Reference] = allocateMap(MapKind_Reference, sizeof(Map))) == NULL)
    76         return false;
    77     if ((maps_[MapKind_MetaArray] = allocateMap(MapKind_MetaArray, sizeof(Map))) == NULL)
    78         return false;
    79     if ((maps_[MapKind_MetaEnvironment] = allocateMap(MapKind_MetaEnvironment, sizeof(Map))) == NULL)
    80         return false;
    81     if ((maps_[MapKind_Module] = allocateMap(MapKind_Module, sizeof(Map))) == NULL)
    82         return false;
    83     if ((maps_[MapKind_Function] = allocateMap(MapKind_Function, sizeof(Map))) == NULL)
    84         return false;
    85     if ((maps_[MapKind_String] = allocateMap(MapKind_String, sizeof(Map))) == NULL)
    86         return false;
    87     if ((maps_[MapKind_Native] = allocateMap(MapKind_Native, sizeof(Map))) == NULL)
    88         return false;
    89     if ((maps_[MapKind_FreeRegion] = allocateMap(MapKind_FreeRegion, sizeof(Map))) == NULL)
    90         return false;
    91     if ((maps_[MapKind_EnvironmentSlotDescriptorArray] =
    92          allocateMap(MapKind_EnvironmentSlotDescriptorArray, sizeof(Map))) == NULL)
    93     {
    94         return false;
    95     }
    96 
    97     types_ = new TypeManager(this);
    98     if (!types_ || !types_->initialize())
    99         return false;
   100 
   101     // Create the cached array maps for generic arrays. This is for the API
   102     // version of Invoke(), which needs to make arrays very quickly from C++.
   103     {
   104         // Generic "cell" array (contents do not matter, just non-gc things).
   105         Local<Type> type(this, types_->getPrimitive(PrimitiveType_Int32));
   106         if (!type)
   107             return false;
   108 
   109         type = types_->unsafeArray(type, Type::UNKNOWN_SIZE, false);
   110         if (!type)
   111             return false;
   112 
   113         Local<ArrayMap> contained(this);
   114         genericArrayMap_ = ArrayMap::New(this, type, contained);
   115         if (!genericArrayMap_)
   116             return false;
   117 
   118         type = types_->getPrimitive(PrimitiveType_Char);
   119         if (!type)
   120             return false;
   121 
   122         type = types_->unsafeArray(type, Type::UNKNOWN_SIZE, false);
   123         if (!type)
   124             return false;
   125 
   126         charArrayMap_ = ArrayMap::New(this, type, contained);
   127         if (!charArrayMap_)
   128             return false;
   129     }
   130 
   131     return true;
   132 }
   133 
   134 Map *
   135 Zone::allocateMap(MapKind kind, size_t bytes, MapKind parent)
   136 {
   137     assert(maps_[parent]);
   138     Map *map = heap_.allocateMap(kind, bytes);
   139     if (!map)
   140         return NULL;
   141     map->init(maps_[parent]);
   142     return map;
   143 }
   144 
   145 void
   146 Zone::accept(VirtualObjectVisitor *visitor)
   147 {
   148     for (unsigned i = 0; i < MapKinds_Total; i++)
   149         visitor->visit(maps_[i].address());
   150     visitor->visit(charArrayMap_.address());
   151     visitor->visit(genericArrayMap_.address());
   152     types()->accept(visitor);
   153 
   154     Local<Object> *local = lastLocalRoot_;
   155     while (local) {
   156         visitor->visit(local->address());
   157         local = local->prev();
   158     }
   159 
   160     globalRoots_->accept(visitor);
   161     rootScopes_.accept(visitor);
   162 
   163     stack_.accept(visitor);
   164 }
   165 
   166 String *
   167 Zone::makeSymbol(const char *str, size_t length)
   168 {
   169     return symbols_->add(str, length);
   170 }
   171 
   172 String *
   173 Zone::makeSymbol(const char *str)
   174 {
   175     return makeSymbol(str, strlen(str));
   176 }
   177 
   178 bool
   179 Zone::hasPendingException()
   180 {
   181     return hasPendingException_;
   182 }
   183 
   184 void
   185 Zone::reportOutOfMemory()
   186 {
   187     
   188 }
   189 
   190 void
   191 Zone::reportError(Message message, ...)
   192 {
   193     va_list ap;
   194     va_start(ap, message);
   195     reportErrorVA(message, ap);
   196     va_end(ap);
   197 }
   198 
   199 #if defined(_MSC_VER)
   200 # define VA_COPY(to, from)  to = from
   201 #else
   202 # define VA_COPY(to, from)  va_copy(to, from)
   203 #endif
   204 
   205 static char *
   206 BuildErrorMessage(const char *format, va_list ap)
   207 {
   208     va_list use;
   209     VA_COPY(use, ap);
   210 
   211     // We over-allocate and zero terminate ahead of time, since LIBCRT's
   212     // version of vsnprintf is screwy.
   213     size_t size = 255;
   214     char *buffer = (char *)calloc(size + 1, 1);
   215     if (!buffer)
   216         return NULL;
   217 
   218     for (;;) {
   219         int r = vsnprintf(buffer, size, format, use);
   220 
   221         if (r > -1 && size_t(r) < size)
   222             return buffer;
   223        
   224 #if defined(_MSC_VER)
   225         if (r < 0)
   226             size *= 2;
   227 #else
   228         if (r > -1)
   229             size = size_t(r) + 1;
   230         else
   231             size *= 2;
   232 #endif
   233 
   234         free(buffer);
   235         if ((buffer = (char *)calloc(size + 1, 1)) == NULL)
   236             return NULL;
   237 
   238         VA_COPY(use, ap);
   239     }
   240 }
   241 
   242 void
   243 Zone::reportErrorVA(Message message, va_list ap)
   244 {
   245     char *report = BuildErrorMessage(Messages[message].format, ap);
   246     if (!report) {
   247         reportOutOfMemory();
   248         return;
   249     }
   250 
   251     if (reporter_) {
   252         // Reporters can re-enter. When we start having actual exception
   253         // objects that can be caught and inspected, this code will have to
   254         // save and restore the exception state.
   255         reporter_->onUncaughtException(report);
   256     }
   257 
   258     hasPendingException_ = true;
   259 
   260     free(report);
   261 }
   262 
   263 void
   264 Zone::beginCompilationErrors(const char *file)
   265 {
   266     if (reporter_)
   267         reporter_->beginCompilationErrors(file);
   268 }
   269 
   270 void
   271 Zone::reportCompilationError(Message message, unsigned line, unsigned col, va_list ap)
   272 {
   273     char *report = BuildErrorMessage(Messages[message].format, ap);
   274     if (!report) {
   275         reportOutOfMemory();
   276         return;
   277     }
   278 
   279     if (reporter_) {
   280         // Reporters can re-enter. When we start having actual exception
   281         // objects that can be caught and inspected, this code will have to
   282         // save and restore the exception state.
   283         reporter_->reportCompilationError(report, line, col);
   284     }
   285 
   286     free(report);
   287 }
   288 
   289 void
   290 Zone::endCompilationErrors()
   291 {
   292     if (reporter_)
   293         reporter_->endCompilationErrors();
   294 }
   295 
   296 void
   297 Zone::installErrorReporter(Ke::IMessageReporter *reporter)
   298 {
   299     reporter_ = reporter;
   300 }
   301 
   302 void
   303 ZoneAllocatorPolicy::reportOutOfMemory()
   304 {
   305     ZONE()->reportOutOfMemory();
   306 }
   307 
   308 void
   309 ZoneAllocatorPolicy::reportAllocationOverflow()
   310 {
   311     ZONE()->reportError(Message_AllocationOverflow);
   312 }