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