jitcraft/Interpreter.cpp
changeset 12 75e385f68b7e
parent 10 0c3bcd50e361
child 14 0784ac5cc347
     1.1 --- a/jitcraft/Interpreter.cpp	Fri Jun 29 19:35:17 2012 -0700
     1.2 +++ b/jitcraft/Interpreter.cpp	Sat Jun 30 19:38:53 2012 -0700
     1.3 @@ -19,6 +19,7 @@
     1.4  #include "Modules.h"
     1.5  #include "Zone.h"
     1.6  #include "Types.h"
     1.7 +#include "Array.h"
     1.8  
     1.9  using namespace jc;
    1.10  
    1.11 @@ -65,123 +66,28 @@
    1.12      return true;
    1.13  }
    1.14  
    1.15 -struct ArrayBuilder
    1.16 +// Generate an array with completely static sizes.
    1.17 +static Array *
    1.18 +GenerateArray(Zone *zone, ArrayMap *map)
    1.19  {
    1.20 -    char *base;
    1.21 -    unsigned width;
    1.22 -    unsigned ndims;
    1.23 -    int *dims;
    1.24 -};
    1.25 -
    1.26 -// Unlike the old SourcePawn VM, we do not allocate the final levels in one
    1.27 -// contiguous block. This might result in different cache behavior, but who
    1.28 -// knows. This algorithm is simpler and faster.
    1.29 -//
    1.30 -// In pawn, an array reference a[b][c]
    1.31 -//
    1.32 -//   (&a[b] + a[b])[c]
    1.33 -//
    1.34 -// That is, when hopping to the next array, the slot is relative to the
    1.35 -// current address, not absolute.
    1.36 -//
    1.37 -static unsigned
    1.38 -GenerateIndirectionVectors(const ArrayBuilder &builder, unsigned cursor, unsigned level)
    1.39 -{
    1.40 -    unsigned current = cursor;
    1.41 +    assert(map->type()->elements() != -1);
    1.42  
    1.43 -    // Reserve space for this level.
    1.44 -    cursor += builder.dims[level] *
    1.45 -              ((level == builder.ndims - 1) ? builder.width : sizeof(unsigned));
    1.46 -
    1.47 -    // If we're at the last level, we're done.
    1.48 -    if (level == builder.ndims - 1)
    1.49 -        return cursor;
    1.50 -
    1.51 -    for (unsigned i = 0; i < unsigned(builder.dims[level]); i++) {
    1.52 -        // Hide the number of elements in the next vector, right behind it.
    1.53 -        *reinterpret_cast<unsigned *>(builder.base + cursor) = builder.dims[level + 1];
    1.54 -        cursor += sizeof(unsigned);
    1.55 -
    1.56 -        // The next hop will be generated at |cursor|, which will be read from |current|.
    1.57 -        *reinterpret_cast<unsigned *>(builder.base + current) = cursor - current;
    1.58 -
    1.59 -        cursor = GenerateIndirectionVectors(builder, cursor, level + 1);
    1.60 -        current += sizeof(unsigned);
    1.61 -    }
    1.62 -
    1.63 -    return cursor;
    1.64 -}
    1.65 -
    1.66 -UnsafeArray *
    1.67 -jc::AllocateUnsafeArray(unsigned width, unsigned ndims, int *dims)
    1.68 -{
    1.69 -    // Sanity check.
    1.70 -    if (!CheckDimensionSize(dims[ndims - 1], width))
    1.71 +    // :TODO: use Local
    1.72 +    Array *array = Array::New(zone, map, map->type()->elements(), Heap::Tenure_Stack);
    1.73 +    if (!array)
    1.74          return NULL;
    1.75  
    1.76 -    // All innermost vectors must be this size.
    1.77 -    size_t nbytes = dims[ndims - 1] * width + sizeof(unsigned);
    1.78 +    if (map->type()->levels() == 1)
    1.79 +        return array;
    1.80  
    1.81 -    if (ndims == 1) {
    1.82 -        // Fast path, no complicated indirection vectors.
    1.83 -        unsigned *ptr = (unsigned *)ZONE()->unsafeStack().allocate(nbytes);
    1.84 -        if (!ptr)
    1.85 +    for (unsigned i = 0; i < unsigned(map->type()->elements()); i++) {
    1.86 +        Array *sub = GenerateArray(zone, map->contained());
    1.87 +        if (!sub)
    1.88              return NULL;
    1.89 -        memset(ptr, 0, nbytes);
    1.90 -
    1.91 -        *ptr = dims[0];
    1.92 -
    1.93 -        UnsafeArray *array = reinterpret_cast<UnsafeArray *>(ptr + 1);
    1.94 -        return array;
    1.95 +        array->writeObject(zone, i, sub);
    1.96      }
    1.97  
    1.98 -    // Add space from the innermost indrect array to the outermost. Each time,
    1.99 -    // we must also add space for the indirection slots.
   1.100 -    for (unsigned i = ndims - 2; i < ndims; i--) {
   1.101 -        if (!CheckDimensionSize(dims[ndims - 1], sizeof(unsigned) * 2))
   1.102 -            return NULL;
   1.103 -
   1.104 -        if (!IsUint32MultiplySafe(nbytes, dims[i])) {
   1.105 -            assert(false);
   1.106 -            return NULL;
   1.107 -        }
   1.108 -
   1.109 -        nbytes *= dims[i];
   1.110 -
   1.111 -        // Add space for the indirection vectors at this level.
   1.112 -        if (!IsUint32AddSafe(nbytes, dims[i] * sizeof(unsigned) + sizeof(unsigned))) {
   1.113 -            assert(false);
   1.114 -            return NULL;
   1.115 -        }
   1.116 -
   1.117 -        // Reserve space for each indirection vector.
   1.118 -        nbytes += dims[i] * sizeof(unsigned);
   1.119 -
   1.120 -        // Reserve space for our own indirection vector.
   1.121 -        nbytes += sizeof(unsigned);
   1.122 -    }
   1.123 -
   1.124 -    void *base = ZONE()->unsafeStack().allocate(nbytes);
   1.125 -    if (!base)
   1.126 -        return NULL;
   1.127 -    memset(base, 0, nbytes);
   1.128 -
   1.129 -    ArrayBuilder array;
   1.130 -    array.base = (char *)base;
   1.131 -    array.dims = dims;
   1.132 -    array.ndims = ndims;
   1.133 -    array.width = width;
   1.134 -
   1.135 -    unsigned cursor = 0;
   1.136 -
   1.137 -    // Hide the length behind the array.
   1.138 -    *reinterpret_cast<unsigned *>(array.base + cursor) = dims[0];
   1.139 -    cursor += sizeof(unsigned);
   1.140 -    
   1.141 -    cursor = GenerateIndirectionVectors(array, cursor, 0);
   1.142 -    assert(cursor == nbytes);
   1.143 -
   1.144 -    return reinterpret_cast<UnsafeArray *>(reinterpret_cast<unsigned *>(base) + 1);
   1.145 +    return array;
   1.146  }
   1.147  
   1.148  bool
   1.149 @@ -455,32 +361,18 @@
   1.150      break;
   1.151  }
   1.152  
   1.153 -case OP_STACKARRAY:
   1.154 -{
   1.155 -    unsigned width = top.pc[1];
   1.156 -    unsigned ndims = top.pc[2];
   1.157 -    UnsafeArray *ptr = AllocateUnsafeArray(width, ndims, reinterpret_cast<int *>(top.pc + 3));
   1.158 -    if (!ptr)
   1.159 -        return false;
   1.160 -
   1.161 -    top.sp->unsafeArray = ptr;
   1.162 -    top.sp++;
   1.163 -    top.pc += 3 + ndims * sizeof(int);
   1.164 -    continue;
   1.165 -}
   1.166 -
   1.167  case OP_BOUNDS_STA:
   1.168  {
   1.169 -    UnsafeArray *array = top.sp[-2].unsafeArray;
   1.170 +    Array *array = top.sp[-2].array;
   1.171      int index = top.sp[-1].i32;
   1.172 -    if (index < 0 || unsigned(index) >= array->length())
   1.173 +    if (index < 0 || unsigned(index) >= array->nelements())
   1.174          return false;
   1.175      break;
   1.176  }
   1.177  
   1.178  case OP_GETARRAY_I:
   1.179  {
   1.180 -    UnsafeArray *array = top.sp[-2].unsafeArray;
   1.181 +    Array *array = top.sp[-2].array;
   1.182      int index = top.sp[-1].i32;
   1.183      top.sp[-2].i32 = array->readInt32(index);
   1.184      top.sp--;
   1.185 @@ -489,7 +381,7 @@
   1.186  
   1.187  case OP_GETARRAY_F:
   1.188  {
   1.189 -    UnsafeArray *array = top.sp[-2].unsafeArray;
   1.190 +    Array *array = top.sp[-2].array;
   1.191      int index = top.sp[-1].i32;
   1.192      top.sp[-2].f = array->readFloat(index);
   1.193      top.sp--;
   1.194 @@ -498,7 +390,7 @@
   1.195  
   1.196  case OP_SETARRAY_I:
   1.197  {
   1.198 -    UnsafeArray *array = top.sp[-3].unsafeArray;
   1.199 +    Array *array = top.sp[-3].array;
   1.200      int index = top.sp[-2].i32;
   1.201      array->writeInt32(index, top.sp[-1].i32);
   1.202      top.sp[-3] = top.sp[-1];
   1.203 @@ -508,7 +400,7 @@
   1.204  
   1.205  case OP_SETARRAY_F:
   1.206  {
   1.207 -    UnsafeArray *array = top.sp[-3].unsafeArray;
   1.208 +    Array *array = top.sp[-3].array;
   1.209      int index = top.sp[-2].i32;
   1.210      array->writeFloat(index, top.sp[-1].f);
   1.211      top.sp[-3] = top.sp[-1];
   1.212 @@ -518,9 +410,9 @@
   1.213  
   1.214  case OP_GETARRAY_P:
   1.215  {
   1.216 -    UnsafeArray *array = top.sp[-2].unsafeArray;
   1.217 +    Array *array = top.sp[-2].array;
   1.218      int index = top.sp[-1].i32;
   1.219 -    top.sp[-2].unsafeArray = array->indirect(index);
   1.220 +    top.sp[-2].array = Array::cast(array->readObject(index));
   1.221      top.sp--;
   1.222      break;
   1.223  }
   1.224 @@ -533,12 +425,31 @@
   1.225      break;
   1.226  }
   1.227  
   1.228 -case OP_UNWIND:
   1.229 +case OP_LIFOARRAY:
   1.230 +{
   1.231 +    // :TODO: use Local
   1.232 +    ArrayMap *map = ArrayMap::cast(frame->code()->map(READ_UINT32(top.pc)));
   1.233 +    Array *array = GenerateArray(ZONE(), map);
   1.234 +    if (!array) {
   1.235 +        assert(false);
   1.236 +        return false;
   1.237 +    }
   1.238 +    top.sp->obj = array;
   1.239 +    top.sp++;
   1.240 +    break;
   1.241 +}
   1.242 +
   1.243 +case OP_SAVELIFO:
   1.244  {
   1.245      unsigned slot = READ_UINT32(top.pc);
   1.246 -    UnsafeArray *ua = locals[slot].unsafeArray;
   1.247 -    assert((char *)ua >= (char *)frame->prevUnsafeStack());
   1.248 -    ZONE()->unsafeStack().unwind(ua->allocationBase());
   1.249 +    locals[slot].address = ZONE()->heap().lifoPosition();
   1.250 +    break;
   1.251 +}
   1.252 +
   1.253 +case OP_UNWINDLIFO:
   1.254 +{
   1.255 +    unsigned slot = READ_UINT32(top.pc);
   1.256 +    ZONE()->heap().unwindLifo(locals[slot].address);
   1.257      break;
   1.258  }
   1.259