Restructure Array so the elements vector can be replaced.
authorDavid Anderson <dvander@alliedmods.net>
Sun Sep 16 21:34:10 2012 -0700 (2012-09-16)
changeset 188bab29bcec7fe
parent 187 9308d52205a0
child 189 eee18bf13c9b
Restructure Array so the elements vector can be replaced.
src/API.cpp
src/Array.cpp
src/Array.h
src/BytecodeCompiler.cpp
src/BytecodeEmitter.h
src/FixedArray.cpp
src/FixedArray.h
src/Interpreter.cpp
src/Messages.tbl
src/ObjectVisitor.h
src/Opcodes.cpp
src/Opcodes.tbl
src/Reference.cpp
src/Reference.h
src/SemanticAnalysis.cpp
src/TypeManager.cpp
src/TypeManager.h
src/Types.cpp
src/Types.h
src/Zone.cpp
src/Zone.h
     1.1 --- a/src/API.cpp	Sun Sep 16 19:02:23 2012 -0700
     1.2 +++ b/src/API.cpp	Sun Sep 16 21:34:10 2012 -0700
     1.3 @@ -489,34 +489,36 @@
     1.4  
     1.5            case Ke::Parameter::Array:
     1.6            {
     1.7 -            ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->genericArrayMap());
     1.8 +            ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->externalGenericArrayMap());
     1.9              if (params[i].writeback()) {
    1.10 -                slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].length(),
    1.11 -                                              params[i].buffer(), Heap::Tenure_Stack);
    1.12 +                slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].buffer(),
    1.13 +                                              params[i].length(), Heap::Tenure_Stack);
    1.14                  if (!slot.obj)
    1.15                      return false;
    1.16              } else {
    1.17                  Array *array = Array::New1D(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
    1.18                  if (!slot.obj)
    1.19                      return false;
    1.20 -                memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(int));
    1.21 +                if (params[i].length())
    1.22 +                    memcpy(array->bytes(), params[i].buffer(), params[i].length() * sizeof(int));
    1.23              }
    1.24              break;
    1.25            }
    1.26  
    1.27            case Ke::Parameter::CharArray:
    1.28            {
    1.29 -            ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->charArrayMap());
    1.30 +            ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->externalCharArrayMap());
    1.31              if (params[i].writeback()) {
    1.32 -                slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].length(),
    1.33 -                                              params[i].buffer(), Heap::Tenure_Stack);
    1.34 +                slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].buffer(),
    1.35 +                                              params[i].length(), Heap::Tenure_Stack);
    1.36                  if (!slot.obj)
    1.37                      return false;
    1.38              } else {
    1.39                  Array *array = Array::New1D(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
    1.40                  if (!slot.obj)
    1.41                      return false;
    1.42 -                memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(char));
    1.43 +                if (params[i].length())
    1.44 +                    memcpy(array->bytes(), params[i].buffer(), params[i].length() * sizeof(char));
    1.45              }
    1.46              break;
    1.47            }
     2.1 --- a/src/Array.cpp	Sun Sep 16 19:02:23 2012 -0700
     2.2 +++ b/src/Array.cpp	Sun Sep 16 21:34:10 2012 -0700
     2.3 @@ -18,6 +18,7 @@
     2.4   */
     2.5  #include <string.h>
     2.6  #include "Array.h"
     2.7 +#include "FixedArray.h"
     2.8  #include "Heap.h"
     2.9  #include "Zone.h"
    2.10  #include "Structures.h"
    2.11 @@ -58,37 +59,60 @@
    2.12      return map;
    2.13  }
    2.14  
    2.15 -static inline size_t
    2.16 -SizeFor(Type *type, unsigned elements)
    2.17 -{
    2.18 -    if (type->contained()->isTraceable())
    2.19 -        return sizeof(Array) + elements * sizeof(ke::Object *);
    2.20 -    if (type->contained()->isInt32())
    2.21 -        return sizeof(Array) + elements * sizeof(int);
    2.22 -    if (type->contained()->primitive() == PrimitiveType_Char)
    2.23 -        return sizeof(Array) + elements * sizeof(char);
    2.24 -    assert(type->contained()->isFloat());
    2.25 -    return elements * sizeof(float);
    2.26 -}
    2.27 -
    2.28  Array *
    2.29  Array::NewRaw(Zone *zone, Handle<ArrayMap> map, unsigned nelements, Heap::Tenure tenure)
    2.30  {
    2.31 -    if (nelements > (INT_MAX / SizeFor(map->type(), 1))) {
    2.32 +    if (nelements > (INT_MAX / SizeForElement(map->type()))) {
    2.33          zone->reportError(Message_ArraySizeTooBig);
    2.34          return NULL;
    2.35      }
    2.36  
    2.37 -    size_t elementBytes = SizeFor(map->type(), nelements);
    2.38 -    size_t bytes = sizeof(Array) + elementBytes;
    2.39 +    size_t bytes = sizeof(Array);
    2.40 +    if (map->type()->hasInlineElements())
    2.41 +        bytes += SizeForElement(map->type()) * nelements;
    2.42 +
    2.43      Local<Array> array(zone, Array::cast(zone->allocate(map, bytes, tenure)));
    2.44      if (!array)
    2.45          return NULL;
    2.46  
    2.47 -    array->nelements_ = nelements;
    2.48 -    array->elements_ = (Array *)array + 1;
    2.49 -    memset(array->vec(), 0, elementBytes);
    2.50 +    array->length_ = 0;
    2.51 +    array->elements_ = NULL;
    2.52 +
    2.53 +    if (map->type()->hasInlineElements()) {
    2.54 +        // This must be a fixed array containing no traceables.
    2.55 +        assert(nelements > 0);
    2.56 +        assert(map->type()->isFixedLength());
    2.57 +        assert(!map->type()->contained()->isTraceable());
    2.58 +
    2.59 +        // Compute an interior |elements_| pointer, such that if elements_
    2.60 +        // is accessed like a FixedArray, we reach the appropriate vector.
    2.61 +        array->elements_ = Address((Array *)array + 1) - ByteArray::offsetToElements();
    2.62 +        array->length_ = nelements;
    2.63 +        memset(array->bytes(), 0, SizeForElement(map->type()) * nelements);
    2.64 +        return array;
    2.65 +    }
    2.66  
    2.67 +    // If there is nothing to allocate, we don't bother creating elements yet.
    2.68 +    if (!nelements)
    2.69 +        return array;
    2.70 +
    2.71 +    if (!map->type()->contained()->isTraceable()) {
    2.72 +        size_t nbytes = SizeForElement(map->type()) * nelements;
    2.73 +        Local<ByteArray> elements(zone, ByteArray::New(zone, nbytes, tenure));
    2.74 +        if (!elements)
    2.75 +            return NULL;
    2.76 +
    2.77 +        array->updateLengthAndElements(zone, nelements, elements);
    2.78 +        return array;
    2.79 +    }
    2.80 +
    2.81 +    Local<FixedArray> elements(zone, FixedArray::New(zone, nelements, tenure));
    2.82 +    if (!elements)
    2.83 +        return NULL;
    2.84 +
    2.85 +    array->updateLengthAndElements(zone, nelements, elements);
    2.86 +
    2.87 +    // If this is an array of structs, we're required to allocate those structs now.
    2.88      if (map->type()->contained()->isStruct()) {
    2.89          Local<StructMap> childMap(zone, StructMap::cast(map->type()->contained()->newMap()));
    2.90          Local<Struct> child(zone);
    2.91 @@ -97,7 +121,7 @@
    2.92              if (!child)
    2.93                  return NULL;
    2.94  
    2.95 -            array->writeObject(zone, i, child);
    2.96 +            elements->set(zone, i, child);
    2.97          }
    2.98      }
    2.99  
   2.100 @@ -211,15 +235,15 @@
   2.101  }
   2.102  
   2.103  Array *
   2.104 -Array::NewExternal(Zone *zone, Handle<ArrayMap> map, uint32 nelements, void *buffer,
   2.105 +Array::NewExternal(Zone *zone, Handle<ArrayMap> map, void *buffer, unsigned length,
   2.106                     Heap::Tenure tenure)
   2.107  {
   2.108      Local<Array> array(zone, Array::cast(zone->allocate(map, sizeof(Array), tenure)));
   2.109      if (!array)
   2.110          return NULL;
   2.111  
   2.112 -    array->nelements_ = nelements;
   2.113 -    array->elements_ = buffer;
   2.114 +    array->length_ = length;
   2.115 +    array->elements_ = Address(buffer) - ByteArray::offsetToElements();
   2.116      return array;
   2.117  }
   2.118  
     3.1 --- a/src/Array.h	Sun Sep 16 19:02:23 2012 -0700
     3.2 +++ b/src/Array.h	Sun Sep 16 21:34:10 2012 -0700
     3.3 @@ -22,6 +22,7 @@
     3.4  #include "Heap.h"
     3.5  #include "Handles.h"
     3.6  #include "Types.h"
     3.7 +#include "FixedArray.h"
     3.8  
     3.9  namespace ke {
    3.10  
    3.11 @@ -31,34 +32,59 @@
    3.12  {
    3.13      friend class ArrayMap;
    3.14  
    3.15 -    uint32 nelements_;
    3.16 -    void *elements_;
    3.17 +    // Note: we do not write barrier |elements_|, since it can be set to
    3.18 +    // arbitrary pointers.
    3.19 +    uint32 length_;
    3.20 +    union {
    3.21 +        void *elements_;
    3.22 +        Object *objelements_;
    3.23 +    };
    3.24 +
    3.25 +  private:
    3.26 +    void updateLengthAndElements(Zone *zone, unsigned length, Object *array) {
    3.27 +        length_ = length;
    3.28 +        write(zone, &objelements_, array);
    3.29 +    }
    3.30  
    3.31    public:
    3.32      static Array *NewFixed(Zone *zone, Handle<ArrayMap> map, Heap::Tenure = Heap::Tenure_Default);
    3.33      static Array *NewString(Zone *zone, Handle<ArrayMap> map, Address buffer, size_t length, Heap::Tenure = Heap::Tenure_Default);
    3.34      static Array *NewSized(Zone *zone, Handle<ArrayMap> map, int sizes[MAX_ARRAY_DEPTH], Heap::Tenure = Heap::Tenure_Default);
    3.35 -    static Array *NewExternal(Zone *zone, Handle<ArrayMap> map, uint32 nelements,
    3.36 -                              void *elements, Heap::Tenure = Heap::Tenure_Default);
    3.37  
    3.38      static Array *New1D(Zone *zone, Handle<ArrayMap> map, uint32 elements, Heap::Tenure tenure = Heap::Tenure_Default);
    3.39      static Array *NewEmpty(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure = Heap::Tenure_Default);
    3.40      static Array *NewRaw(Zone *zone, Handle<ArrayMap> map, unsigned nelements, Heap::Tenure tenure);
    3.41  
    3.42 +    static Array *NewExternal(Zone *zone,
    3.43 +                              Handle<ArrayMap> map,
    3.44 +                              void *buffer,
    3.45 +                              unsigned length,
    3.46 +                              Heap::Tenure tenure = Heap::Tenure_Default);
    3.47 +
    3.48      uint32 length() {
    3.49 -        return nelements_;
    3.50 +        return length_;
    3.51      }
    3.52 -    void *vec() {
    3.53 -        return elements_;
    3.54 -    }
    3.55 +
    3.56 +    inline Type *type();
    3.57  
    3.58      inline int *int32Vec();
    3.59      inline float *floatVec();
    3.60 -    inline Object **objVec();
    3.61      inline char *chars();
    3.62 +    inline void *bytes();
    3.63 +
    3.64  
    3.65 -    inline Type *type();
    3.66 -    inline size_t elementSize();
    3.67 +    static inline size_t SizeForElement(Type *type) {
    3.68 +        if (type->contained()->isTraceable())
    3.69 +            return sizeof(ke::Object *);
    3.70 +        if (type->contained()->isInt32())
    3.71 +            return sizeof(int);
    3.72 +        if (type->contained()->primitive() == PrimitiveType_Char)
    3.73 +            return sizeof(char);
    3.74 +        assert(type->contained()->isFloat());
    3.75 +        return sizeof(float);
    3.76 +    }
    3.77 +
    3.78 +    inline size_t objSize(ArrayMap *map);
    3.79  
    3.80      int readInt32(size_t index) {
    3.81          assert(index < length());
    3.82 @@ -84,27 +110,18 @@
    3.83          assert(index < length());
    3.84          floatVec()[index] = f;
    3.85      }
    3.86 -    inline void *slotPtr(size_t index);
    3.87      Object *readObject(size_t index) {
    3.88 -        assert(index < length());
    3.89 -        return objVec()[index];
    3.90 +        return FixedArray::cast(objelements_)->at(index);
    3.91      }
    3.92      void writeObject(Zone *zone, size_t index, Object *ptr) {
    3.93 -        assert(index < length());
    3.94 -        write(zone, &objVec()[index], ptr);
    3.95 +        FixedArray::cast(objelements_)->set(zone, index, ptr);
    3.96      }
    3.97  
    3.98 -    bool isExternal() {
    3.99 -        // Inline arrays always have their elements pointing at the next slot.
   3.100 -        Address buffer = reinterpret_cast<Address>(elements_);
   3.101 -        return buffer != reinterpret_cast<Address>(this + 1);
   3.102 +    // GC Descriptor.
   3.103 +    static inline size_t offsetOfElements() {
   3.104 +        return offsetof(Array, objelements_);
   3.105      }
   3.106 -
   3.107 -    static inline size_t SizeOf(Array *array) {
   3.108 -        if (array->isExternal())
   3.109 -            return sizeof(Array);
   3.110 -        return sizeof(Array) + array->length() * array->elementSize();
   3.111 -    }
   3.112 +    // End GC Descriptor.
   3.113  
   3.114      static Array *cast(Object *obj) {
   3.115          assert(!obj || obj->is(MapKind_Array));
   3.116 @@ -136,44 +153,37 @@
   3.117      }
   3.118  };
   3.119  
   3.120 +inline void *
   3.121 +Array::bytes()
   3.122 +{
   3.123 +    assert(!type()->contained()->isTraceable());
   3.124 +    assert(type()->hasInlineElements() ||
   3.125 +           type()->isExternalArray() ||
   3.126 +           !length() ||
   3.127 +           ByteArray::cast((Object *)elements_));
   3.128 +
   3.129 +    return Address(elements_) + ByteArray::offsetToElements();
   3.130 +}
   3.131 +
   3.132  inline int *
   3.133  Array::int32Vec()
   3.134  {
   3.135 -    assert(type()->levels() == 1);
   3.136      assert(type()->contained()->isInt32());
   3.137 -    return reinterpret_cast<int *>(vec());
   3.138 +    return reinterpret_cast<int *>(bytes());
   3.139  }
   3.140  
   3.141  inline float *
   3.142  Array::floatVec()
   3.143  {
   3.144 -    assert(type()->levels() == 1);
   3.145      assert(type()->contained()->isFloat());
   3.146 -    return reinterpret_cast<float *>(vec());
   3.147 -}
   3.148 -
   3.149 -inline Object **
   3.150 -Array::objVec()
   3.151 -{
   3.152 -    assert(type()->contained()->isTraceable());
   3.153 -    return reinterpret_cast<Object **>(vec());
   3.154 -}
   3.155 -
   3.156 -inline void *
   3.157 -Array::slotPtr(size_t index)
   3.158 -{
   3.159 -    assert(type()->contained()->primitive() == PrimitiveType_Int32 ||
   3.160 -           type()->contained()->primitive() == PrimitiveType_Float);
   3.161 -    assert(index < length());
   3.162 -    return reinterpret_cast<int *>(vec()) + index;
   3.163 +    return reinterpret_cast<float *>(bytes());
   3.164  }
   3.165  
   3.166  inline char *
   3.167  Array::chars()
   3.168  {
   3.169 -    assert(type()->levels() == 1);
   3.170 -    assert(type()->contained()->primitive() == PrimitiveType_Char);
   3.171 -    return reinterpret_cast<char *>(vec());
   3.172 +    assert(type()->isCharArray());
   3.173 +    return reinterpret_cast<char *>(bytes());
   3.174  }
   3.175  
   3.176  inline Type *
   3.177 @@ -183,20 +193,12 @@
   3.178  }
   3.179  
   3.180  inline size_t
   3.181 -Array::elementSize()
   3.182 +Array::objSize(ArrayMap *map)
   3.183  {
   3.184 -    assert(type()->isArray());
   3.185 -    if (type()->contained()->isArray())
   3.186 -        return sizeof(Object *);
   3.187 -    switch (type()->contained()->primitive()) {
   3.188 -      case PrimitiveType_Float:
   3.189 -        return sizeof(float);
   3.190 -      case PrimitiveType_Int32:
   3.191 -        return sizeof(int);
   3.192 -      default:
   3.193 -        assert(type()->contained()->primitive() == PrimitiveType_Char);
   3.194 -        return sizeof(char);
   3.195 -    }
   3.196 +    assert(this->map() == map);
   3.197 +    if (map->type()->hasInlineElements())
   3.198 +        return sizeof(Array) + Array::SizeForElement(map->type()) * length();
   3.199 +    return sizeof(Array);
   3.200  }
   3.201  
   3.202  }
     4.1 --- a/src/BytecodeCompiler.cpp	Sun Sep 16 19:02:23 2012 -0700
     4.2 +++ b/src/BytecodeCompiler.cpp	Sun Sep 16 21:34:10 2012 -0700
     4.3 @@ -1049,12 +1049,6 @@
     4.4                  Variable *var = arg->toNameProxy()->binding()->toVariable();
     4.5                  __ note_position(node->pos());
     4.6                  __ newref(var);
     4.7 -            } else if (arg->isIndexExpression()) {
     4.8 -                IndexExpression *expr = arg->toIndexExpression();
     4.9 -                expr->left()->accept(this);
    4.10 -                expr->right()->accept(this);
    4.11 -                __ note_position(expr->pos());
    4.12 -                __ arrayref_lifo();
    4.13              } else if (arg->isFieldExpression()) {
    4.14                  FieldExpression *expr = arg->toFieldExpression();
    4.15                  expr->left()->accept(this);
     5.1 --- a/src/BytecodeEmitter.h	Sun Sep 16 19:02:23 2012 -0700
     5.2 +++ b/src/BytecodeEmitter.h	Sun Sep 16 21:34:10 2012 -0700
     5.3 @@ -491,11 +491,6 @@
     5.4          singleByteOp(OP_SLOTREF_LIFO);
     5.5          markOop(1);
     5.6      }
     5.7 -    void arrayref_lifo() {
     5.8 -        recordOops();
     5.9 -        singleByteOp(OP_ARRAYREF_LIFO);
    5.10 -        markOop(1);
    5.11 -    }
    5.12      void fieldref_lifo(unsigned index) {
    5.13          recordOops();
    5.14          ensure(OP_FIELDREF_LIFO_LENGTH);
     6.1 --- a/src/FixedArray.cpp	Sun Sep 16 19:02:23 2012 -0700
     6.2 +++ b/src/FixedArray.cpp	Sun Sep 16 21:34:10 2012 -0700
     6.3 @@ -75,3 +75,4 @@
     6.4      memset(array->raw(), 0, length);
     6.5      return array;
     6.6  }
     6.7 +
     7.1 --- a/src/FixedArray.h	Sun Sep 16 19:02:23 2012 -0700
     7.2 +++ b/src/FixedArray.h	Sun Sep 16 21:34:10 2012 -0700
     7.3 @@ -51,7 +51,7 @@
     7.4          return SizeFor(length());
     7.5      }
     7.6  
     7.7 -    static size_t SizeFor(unsigned length) {
     7.8 +    static inline size_t SizeFor(unsigned length) {
     7.9          return sizeof(FixedArray) + sizeof(Object *) * length;
    7.10      }
    7.11  
    7.12 @@ -74,13 +74,17 @@
    7.13          return length_;
    7.14      }
    7.15      Address raw() {
    7.16 -        return reinterpret_cast<uint8 *>(this + 1);
    7.17 +        return Address(this) + offsetToElements();
    7.18      }
    7.19      size_t objSize() {
    7.20          return SizeFor(length());
    7.21      }
    7.22  
    7.23 -    static size_t SizeFor(unsigned length) {
    7.24 +    static inline size_t offsetToElements() {
    7.25 +        return sizeof(ByteArray);
    7.26 +    }
    7.27 +
    7.28 +    static inline size_t SizeFor(unsigned length) {
    7.29          return sizeof(ByteArray) + sizeof(uint8) * length;
    7.30      }
    7.31  
     8.1 --- a/src/Interpreter.cpp	Sun Sep 16 19:02:23 2012 -0700
     8.2 +++ b/src/Interpreter.cpp	Sun Sep 16 21:34:10 2012 -0700
     8.3 @@ -141,7 +141,8 @@
     8.4             ? source->length() <= dest->length()
     8.5             : source->length() == dest->length());
     8.6  
     8.7 -    memcpy(dest->vec(), source->vec(), source->length() * source->elementSize());
     8.8 +    assert(dest->length());
     8.9 +    memcpy(dest->bytes(), source->bytes(), source->length() * Array::SizeForElement(dest->type()));
    8.10      return true;
    8.11  }
    8.12  
    8.13 @@ -320,7 +321,7 @@
    8.14              cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
    8.15          } else {
    8.16              assert(param->isArray());
    8.17 -            cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
    8.18 +            cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
    8.19          }
    8.20      }
    8.21  
    8.22 @@ -332,7 +333,7 @@
    8.23              cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
    8.24          } else {
    8.25              assert(arg.obj->is(MapKind_Array));
    8.26 -            cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
    8.27 +            cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
    8.28          }
    8.29      }
    8.30  
    8.31 @@ -901,24 +902,6 @@
    8.32      break;
    8.33  }
    8.34  
    8.35 -case OP_ARRAYREF_LIFO:
    8.36 -{
    8.37 -    Local<Array> array(zone, Array::cast(top.sp[-2].obj));
    8.38 -
    8.39 -    int index = top.sp[-1].i32;
    8.40 -    if (index < 0 || unsigned(index) >= array->length()) {
    8.41 -        zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
    8.42 -        goto error;
    8.43 -    }
    8.44 -
    8.45 -    Local<Reference> ref(zone, Reference::NewArray(zone, array, index, Heap::Tenure_Stack));
    8.46 -    if (!ref)
    8.47 -        goto error;
    8.48 -    top.sp[-2].ref = ref;
    8.49 -    top.sp--;
    8.50 -    break;
    8.51 -}
    8.52 -
    8.53  case OP_SLOTREF_LIFO:
    8.54  {
    8.55      Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
     9.1 --- a/src/Messages.tbl	Sun Sep 16 19:02:23 2012 -0700
     9.2 +++ b/src/Messages.tbl	Sun Sep 16 21:34:10 2012 -0700
     9.3 @@ -77,4 +77,5 @@
     9.4  MSG(ExpectedStringLiteral,          SyntaxError,            "expected string literal")
     9.5  MSG(UnexpectedArrayLiteral,         SyntaxError,            "unexpected array literal")
     9.6  MSG(InvalidDimensionSize,           TypeError,              "invalid size %d for dimension %d")
     9.7 +MSG(CannotComputeIndexRef,          SyntaxError,            "cannot use an array index as a reference")
     9.8  
    10.1 --- a/src/ObjectVisitor.h	Sun Sep 16 19:02:23 2012 -0700
    10.2 +++ b/src/ObjectVisitor.h	Sun Sep 16 21:34:10 2012 -0700
    10.3 @@ -117,14 +117,9 @@
    10.4      }
    10.5  
    10.6      size_t iterateArray(Array *array, ArrayMap *map) {
    10.7 -        assert(map->type()->isArray());
    10.8 -        if (map->type()->contained()->isTraceable()) {
    10.9 -            unsigned length = array->length();
   10.10 -            Object **vec = array->objVec();
   10.11 -            for (unsigned i = 0; i < length; i++)
   10.12 -                this->visit(vec + i);
   10.13 -        }
   10.14 -        return Array::SizeOf(array);
   10.15 +        if (!map->type()->fixedLength() || map->type()->contained()->isTraceable())
   10.16 +            visitField(array, Array::offsetOfElements());
   10.17 +        return array->objSize(map);
   10.18      }
   10.19  
   10.20      size_t iterateBox(Box *obj) {
   10.21 @@ -289,7 +284,7 @@
   10.22          return sizeof(Native);
   10.23  
   10.24        case MapKind_Array:
   10.25 -        return Align(Array::SizeOf(Array::cast(obj)), kObjectAlignment);
   10.26 +        return Align(Array::cast(obj)->objSize(ArrayMap::cast(map)), kObjectAlignment);
   10.27  
   10.28        case MapKind_Box:
   10.29          return sizeof(Box);
    11.1 --- a/src/Opcodes.cpp	Sun Sep 16 19:02:23 2012 -0700
    11.2 +++ b/src/Opcodes.cpp	Sun Sep 16 21:34:10 2012 -0700
    11.3 @@ -85,7 +85,6 @@
    11.4             op == OP_VARREF_LIFO ||
    11.5             op == OP_ARGREF_LIFO ||
    11.6             op == OP_SLOTREF_LIFO ||
    11.7 -           op == OP_ARRAYREF_LIFO ||
    11.8             op == OP_COPYARRAY);
    11.9  #endif
   11.10  
   11.11 @@ -179,7 +178,6 @@
   11.12            case OP_GETREF_F:
   11.13            case OP_SETREF_F:
   11.14            case OP_SLOTREF_LIFO:
   11.15 -          case OP_ARRAYREF_LIFO:
   11.16            case OP_COPYARRAY:
   11.17            case OP_COPYSTRUCT:
   11.18            case OP_DUP:
    12.1 --- a/src/Opcodes.tbl	Sun Sep 16 19:02:23 2012 -0700
    12.2 +++ b/src/Opcodes.tbl	Sun Sep 16 21:34:10 2012 -0700
    12.3 @@ -174,23 +174,22 @@
    12.4  OPDEF(OP_VARREF_LIFO,   69,         "varref.lifo",  5,      0,  1)
    12.5  OPDEF(OP_ARGREF_LIFO,   70,         "argref.lifo",  5,      0,  1)
    12.6  OPDEF(OP_SLOTREF_LIFO,  71,         "slotref.lifo", 1,      1,  1)
    12.7 -OPDEF(OP_ARRAYREF_LIFO, 72,         "arrayref.lifo",1,      2,  1)
    12.8 -OPDEF(OP_GETREF_I,      73,         "getref.i",     1,      1,  1)
    12.9 -OPDEF(OP_SETREF_I,      74,         "setref.i",     1,      2,  1)
   12.10 -OPDEF(OP_GETREF_F,      75,         "getref.f",     1,      1,  1)
   12.11 -OPDEF(OP_SETREF_F,      76,         "setref.f",     1,      2,  1)
   12.12 +OPDEF(OP_GETREF_I,      72,         "getref.i",     1,      1,  1)
   12.13 +OPDEF(OP_SETREF_I,      73,         "setref.i",     1,      2,  1)
   12.14 +OPDEF(OP_GETREF_F,      74,         "getref.f",     1,      1,  1)
   12.15 +OPDEF(OP_SETREF_F,      75,         "setref.f",     1,      2,  1)
   12.16  
   12.17  // Pushes an object reference onto the stack.
   12.18 -OPDEF(OP_OBJECT,        77,         "object",       5,      0,  1)
   12.19 +OPDEF(OP_OBJECT,        76,         "object",       5,      0,  1)
   12.20  
   12.21  // Duplicates the top item on the stack.
   12.22 -OPDEF(OP_DUP,           78,         "dup",          1,      1,  2)
   12.23 +OPDEF(OP_DUP,           77,         "dup",          1,      1,  2)
   12.24  
   12.25  // Duplicates the top two items on the stack.
   12.26 -OPDEF(OP_DUP2,          79,         "dup2",         1,      2,  4)
   12.27 +OPDEF(OP_DUP2,          78,         "dup2",         1,      2,  4)
   12.28  
   12.29  // Swaps the two items at the top of the stack.
   12.30 -OPDEF(OP_SWAP,          80,         "swap",         1,      2,  2)
   12.31 +OPDEF(OP_SWAP,          79,         "swap",         1,      2,  2)
   12.32  
   12.33  // Roll operation is the same as Forth. It steals a value on the stack,
   12.34  // shifting all stack values down, and then places the stolen value back at
   12.35 @@ -200,14 +199,14 @@
   12.36  //  sp[-3] = sp[-2]
   12.37  //  sp[-2] = sp[-1]
   12.38  //  sp[-1] = p
   12.39 -OPDEF(OP_ROLL3,         81,         "roll3",        1,      3, 3)
   12.40 +OPDEF(OP_ROLL3,         80,         "roll3",        1,      3, 3)
   12.41  
   12.42  // Pick operation is the same as Forth. It pushes a copy of a slot at a
   12.43  // specific depth.
   12.44  //
   12.45  // push(sp[-n])
   12.46 -OPDEF(OP_PICK2,         82,         "pick2",        1,      2, 3)
   12.47 -OPDEF(OP_PICK3,         83,         "pick3",        1,      3, 4)
   12.48 +OPDEF(OP_PICK2,         81,         "pick2",        1,      2, 3)
   12.49 +OPDEF(OP_PICK3,         82,         "pick3",        1,      3, 4)
   12.50  
   12.51  // Calls a native function. During the course of calling a native, arguments
   12.52  // on the stack are re-pushed to match the cell-based native calling
   12.53 @@ -218,57 +217,57 @@
   12.54  //
   12.55  // [u8 Opcode] [u32 Index] [u32 ArgCount]
   12.56  //
   12.57 -OPDEF(OP_CALLNATIVE,    84,         "callnative",   9,      -1, 1)
   12.58 +OPDEF(OP_CALLNATIVE,    83,         "callnative",   9,      -1, 1)
   12.59  
   12.60  // Returns from a function that does return a value.
   12.61 -OPDEF(OP_RETURNVOID,    85,         "returnvoid",   1,      0, 0)
   12.62 +OPDEF(OP_RETURNVOID,    84,         "returnvoid",   1,      0, 0)
   12.63  
   12.64  // Loads the module of the running function.
   12.65 -OPDEF(OP_MODULE,        86,         "module",       1,      0, 1)
   12.66 +OPDEF(OP_MODULE,        85,         "module",       1,      0, 1)
   12.67  
   12.68  // Loads a function from a module object. The operand is the slot number
   12.69  // in the module.
   12.70 -OPDEF(OP_GETMODULE_FN,  87,         "getmodule.fn", 5,      1, 1)
   12.71 +OPDEF(OP_GETMODULE_FN,  86,         "getmodule.fn", 5,      1, 1)
   12.72  
   12.73  // Opcodes for accessing an environment slot in the global scope.
   12.74 -OPDEF(OP_SETGLOBAL_I,   88,         "setglobal.i",  5,      1, 1)
   12.75 -OPDEF(OP_SETGLOBAL_F,   89,         "setglobal.f",  5,      1, 1)
   12.76 -OPDEF(OP_SETGLOBAL_O,   90,         "setglobal.o",  5,      1, 1)
   12.77 -OPDEF(OP_GETGLOBAL_I,   91,         "getglobal.i",  5,      0, 1)
   12.78 -OPDEF(OP_GETGLOBAL_F,   92,         "getglobal.f",  5,      0, 1)
   12.79 -OPDEF(OP_GETGLOBAL_O,   93,         "getglobal.o",  5,      0, 1)
   12.80 +OPDEF(OP_SETGLOBAL_I,   87,         "setglobal.i",  5,      1, 1)
   12.81 +OPDEF(OP_SETGLOBAL_F,   88,         "setglobal.f",  5,      1, 1)
   12.82 +OPDEF(OP_SETGLOBAL_O,   89,         "setglobal.o",  5,      1, 1)
   12.83 +OPDEF(OP_GETGLOBAL_I,   90,         "getglobal.i",  5,      0, 1)
   12.84 +OPDEF(OP_GETGLOBAL_F,   91,         "getglobal.f",  5,      0, 1)
   12.85 +OPDEF(OP_GETGLOBAL_O,   92,         "getglobal.o",  5,      0, 1)
   12.86  
   12.87  // Reinterprets a 32-bit integer as a float, or vice-versa.
   12.88 -OPDEF(OP_BITS_I2F,      94,         "bits.i2f",     1,      1, 1)
   12.89 -OPDEF(OP_BITS_F2I,      95,         "bits.f2i",     1,      1, 1)
   12.90 +OPDEF(OP_BITS_I2F,      93,         "bits.i2f",     1,      1, 1)
   12.91 +OPDEF(OP_BITS_F2I,      94,         "bits.f2i",     1,      1, 1)
   12.92  
   12.93  // Pushes a boolean value.
   12.94 -OPDEF(OP_TRUE,          96,         "true",         1,      0, 1)
   12.95 -OPDEF(OP_FALSE,         97,         "false",        1,      0, 1)
   12.96 +OPDEF(OP_TRUE,          95,         "true",         1,      0, 1)
   12.97 +OPDEF(OP_FALSE,         96,         "false",        1,      0, 1)
   12.98  
   12.99  // Allocate a struct. The HeapTenure is stored as a byte following pc. The
  12.100  // StructMap to use is specified as an index into the script's Map table.
  12.101  //
  12.102  // Format:
  12.103  //  [u8 op] [u8 tenure] [u32 index]
  12.104 -OPDEF(OP_NEWSTRUCT,     98,         "newstruct",    6,      0, 1)
  12.105 +OPDEF(OP_NEWSTRUCT,     97,         "newstruct",    6,      0, 1)
  12.106  
  12.107  // Performs a struct-to-struct assignment.
  12.108  //   Left = pop()
  12.109  //   Right = pop()
  12.110  //   copy(Left, Right)
  12.111  //   push(Left)
  12.112 -OPDEF(OP_COPYSTRUCT,    99,         "structcopy",   1,      2, 1)
  12.113 +OPDEF(OP_COPYSTRUCT,    98,         "structcopy",   1,      2, 1)
  12.114  
  12.115  // Sets or gets a property in a struct. The index of the field is specified as
  12.116  // a 32-bit integer. Note that these opcodes follow a new style of deriving
  12.117  // their types at runtime.
  12.118 -OPDEF(OP_GETFIELD,      100,        "getfield",     5,      1, 1)
  12.119 -OPDEF(OP_SETFIELD,      101,        "setfield",     5,      2, 1)
  12.120 +OPDEF(OP_GETFIELD,      99,         "getfield",     5,      1, 1)
  12.121 +OPDEF(OP_SETFIELD,      100,        "setfield",     5,      2, 1)
  12.122  
  12.123 -OPDEF(OP_FIELDREF_LIFO, 102,        "fieldref.lifo", 5,     1, 1)
  12.124 +OPDEF(OP_FIELDREF_LIFO, 101,        "fieldref.lifo", 5,     1, 1)
  12.125  
  12.126  // Table-based jump.
  12.127  // [u8 op] [i32 low] [i32 high] [u32 jump] [u32 jumps...]
  12.128 -OPDEF(OP_TABLESWITCH,   103,        "tableswitch",  9,      1, 0)
  12.129 +OPDEF(OP_TABLESWITCH,   102,        "tableswitch",  9,      1, 0)
  12.130  
    13.1 --- a/src/Reference.cpp	Sun Sep 16 19:02:23 2012 -0700
    13.2 +++ b/src/Reference.cpp	Sun Sep 16 21:34:10 2012 -0700
    13.3 @@ -50,18 +50,6 @@
    13.4  }
    13.5  
    13.6  Reference *
    13.7 -Reference::NewArray(Zone *zone, Handle<Array> base, size_t index, Heap::Tenure tenure)
    13.8 -{
    13.9 -    Local<Reference> ref(zone, Reference::cast(zone->allocate(MapKind_Reference, sizeof(Reference), tenure)));
   13.10 -    if (!ref)
   13.11 -        return NULL;
   13.12 -
   13.13 -    ref->location_ = base->slotPtr(index);
   13.14 -    ref->base_ = base;
   13.15 -    return ref;
   13.16 -}
   13.17 -
   13.18 -Reference *
   13.19  Reference::NewField(Zone *zone, Handle<Struct> obj, size_t index, Heap::Tenure tenure)
   13.20  {
   13.21      Local<Reference> ref(zone, Reference::cast(zone->allocate(MapKind_Reference, sizeof(Reference), tenure)));
    14.1 --- a/src/Reference.h	Sun Sep 16 19:02:23 2012 -0700
    14.2 +++ b/src/Reference.h	Sun Sep 16 21:34:10 2012 -0700
    14.3 @@ -40,7 +40,6 @@
    14.4    public:
    14.5      static Reference *NewStack(Zone *zone, void *location, Heap::Tenure tenure = Heap::Tenure_Default);
    14.6      static Reference *NewStack(Zone *zone, const LocalSlot &slot, Heap::Tenure tenure = Heap::Tenure_Default);
    14.7 -    static Reference *NewArray(Zone *zone, Handle<Array> base, size_t index, Heap::Tenure tenure = Heap::Tenure_Default);
    14.8      static Reference *NewField(Zone *zone, Handle<Struct> obj, size_t index, Heap::Tenure tenure = Heap::Tenure_Default);
    14.9  
   14.10      int getInt() {
    15.1 --- a/src/SemanticAnalysis.cpp	Sun Sep 16 19:02:23 2012 -0700
    15.2 +++ b/src/SemanticAnalysis.cpp	Sun Sep 16 21:34:10 2012 -0700
    15.3 @@ -1420,13 +1420,22 @@
    15.4          } else {
    15.5              Local<Type> actual(zone_, type->parameterAt(i));
    15.6  
    15.7 -            if (expression->isIndexExpression() && actual->isArray()) {
    15.8 -                // We special case the ability to pass x[y] into x[], which
    15.9 -                // creates an array slice. We only do this if we know the
   15.10 -                // assignment would otherwise not type-check.
   15.11 -                IndexExpression *index = expression->toIndexExpression();
   15.12 -                if (index->left()->type()->levels() == actual->levels())
   15.13 -                    given = index->left()->type();
   15.14 +            if (expression->isIndexExpression()) {
   15.15 +                // Disabled until we can make it work.
   15.16 +#if 0
   15.17 +                if (actual->isArray()) {
   15.18 +                    // We special case the ability to pass x[y] into x[], which
   15.19 +                    // creates an array slice. We only do this if we know the
   15.20 +                    // assignment would otherwise not type-check.
   15.21 +                    IndexExpression *index = expression->toIndexExpression();
   15.22 +                    if (index->left()->type()->levels() == actual->levels())
   15.23 +                        given = index->left()->type();
   15.24 +                } else
   15.25 +#endif
   15.26 +                if (actual->isReference()) {
   15.27 +                    cc_.reportError(expression->pos(), Message_CannotComputeIndexRef);
   15.28 +                    return;
   15.29 +                }
   15.30              }
   15.31  
   15.32              if (!typeCheckParameter(expression, given, actual))
    16.1 --- a/src/TypeManager.cpp	Sun Sep 16 19:02:23 2012 -0700
    16.2 +++ b/src/TypeManager.cpp	Sun Sep 16 21:34:10 2012 -0700
    16.3 @@ -72,6 +72,12 @@
    16.4  }
    16.5  
    16.6  Type *
    16.7 +TypeManager::newExternalArray(Handle<Type> contained)
    16.8 +{
    16.9 +    return Type::NewExternalArray(zone_, contained);
   16.10 +}
   16.11 +
   16.12 +Type *
   16.13  TypeManager::getReference(Handle<Type> type, bool isConst)
   16.14  {
   16.15      if (!isConst && type->isPrimitive())
    17.1 --- a/src/TypeManager.h	Sun Sep 16 19:02:23 2012 -0700
    17.2 +++ b/src/TypeManager.h	Sun Sep 16 21:34:10 2012 -0700
    17.3 @@ -54,6 +54,7 @@
    17.4      }
    17.5      Type *getReference(Handle<Type> type, bool isConst);
    17.6      Type *newArray(Handle<Type> contained, int elements, bool isConst);
    17.7 +    Type *newExternalArray(Handle<Type> contained);
    17.8      Type *newEnum(Handle<String> name);
    17.9      Type *newFunction(Handle<Type> returnType, Handle<FixedArray> args,
   17.10                        Handle<FixedArray> deafults);
    18.1 --- a/src/Types.cpp	Sun Sep 16 19:02:23 2012 -0700
    18.2 +++ b/src/Types.cpp	Sun Sep 16 21:34:10 2012 -0700
    18.3 @@ -104,6 +104,29 @@
    18.4  }
    18.5  
    18.6  Type *
    18.7 +Type::NewExternalArray(Zone *zone, Handle<Type> contained)
    18.8 +{
    18.9 +    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   18.10 +    if (!type)
   18.11 +        return NULL;
   18.12 +
   18.13 +    assert(contained->isPrimitive());
   18.14 +
   18.15 +    type->kind_ = EXTERNAL_ARRAY;
   18.16 +    type->name_ = NULL;
   18.17 +    type->contained_ = contained;
   18.18 +    type->returnType_ = NULL;
   18.19 +    type->parameters_ = NULL;
   18.20 +    type->defaults_ = NULL;
   18.21 +    type->fields_ = NULL;
   18.22 +    type->newMap_ = NULL;
   18.23 +    type->elements_ = DYNAMIC_ARRAY_SIZE;
   18.24 +    type->levels_ = 1;
   18.25 +    type->const_ = false;
   18.26 +    return type;
   18.27 +}
   18.28 +
   18.29 +Type *
   18.30  Type::NewReference(Zone *zone, Handle<Type> contained, bool isConst)
   18.31  {
   18.32      Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
    19.1 --- a/src/Types.h	Sun Sep 16 19:02:23 2012 -0700
    19.2 +++ b/src/Types.h	Sun Sep 16 21:34:10 2012 -0700
    19.3 @@ -65,6 +65,7 @@
    19.4  
    19.5          // An array is a fixed-length vector of any other type.
    19.6          ARRAY,
    19.7 +        EXTERNAL_ARRAY,
    19.8  
    19.9          // A reference type may only be specified on parameters, and
   19.10          // references may only be computed to primitives or enums.
   19.11 @@ -105,6 +106,7 @@
   19.12      static Type *NewUnchecked(Zone *zone);
   19.13      static Type *NewPrimitive(Zone *zone, PrimitiveType type);
   19.14      static Type *NewArray(Zone *zone, Handle<Type> contained, int elements, bool isConst);
   19.15 +    static Type *NewExternalArray(Zone *zone, Handle<Type> contained);
   19.16      static Type *NewReference(Zone *zone, Handle<Type> contained, bool isConst);
   19.17      static Type *NewFunction(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters,
   19.18                               Handle<FixedArray> defaults);
   19.19 @@ -124,7 +126,7 @@
   19.20          return kind() == PRIMITIVE;
   19.21      }
   19.22      bool isArray() {
   19.23 -        return kind() == ARRAY;
   19.24 +        return kind() == ARRAY || kind() == EXTERNAL_ARRAY;
   19.25      }
   19.26      bool isReference() {
   19.27          return kind() == REFERENCE;
   19.28 @@ -179,6 +181,14 @@
   19.29          assert(isArray());
   19.30          return levels_;
   19.31      }
   19.32 +    bool hasInlineElements() {
   19.33 +        assert(isArray());
   19.34 +
   19.35 +        // We don't allocate traceable elements inline, since there's no
   19.36 +        // point to the optimization; we're going to be allocating lots of
   19.37 +        // objects anyway (in theory).
   19.38 +        return isFixedLength() && !contained()->isTraceable();
   19.39 +    }
   19.40      Type *innermost() {
   19.41          assert(isArray());
   19.42          Type *temp = contained();
   19.43 @@ -203,6 +213,9 @@
   19.44                 contained()->isPrimitive() &&
   19.45                 contained()->primitive() == PrimitiveType_Char;
   19.46      }
   19.47 +    bool isExternalArray() {
   19.48 +        return kind() == EXTERNAL_ARRAY;
   19.49 +    }
   19.50      Type *returnType() {
   19.51          assert(isFunction());
   19.52          return returnType_;
   19.53 @@ -222,7 +235,9 @@
   19.54          return !isPrimitive();
   19.55      }
   19.56      bool isConst() {
   19.57 -        assert(kind() == PRIMITIVE || kind() == ARRAY || kind() == REFERENCE);
   19.58 +        assert(isPrimitive() ||
   19.59 +               isArray() ||
   19.60 +               isReference());
   19.61          return const_;
   19.62      }
   19.63      bool isEnum() {
    20.1 --- a/src/Zone.cpp	Sun Sep 16 19:02:23 2012 -0700
    20.2 +++ b/src/Zone.cpp	Sun Sep 16 21:34:10 2012 -0700
    20.3 @@ -114,24 +114,24 @@
    20.4          if (!type)
    20.5              return false;
    20.6  
    20.7 -        type = types_->newArray(type, Type::DYNAMIC_ARRAY_SIZE, false);
    20.8 +        type = types_->newExternalArray(type);
    20.9          if (!type)
   20.10              return false;
   20.11  
   20.12 -        genericArrayMap_ = ArrayMap::New(this, type);
   20.13 -        if (!genericArrayMap_)
   20.14 +        externalGenericArrayMap_ = ArrayMap::Attach(this, type);
   20.15 +        if (!externalGenericArrayMap_)
   20.16              return false;
   20.17  
   20.18          type = types_->getPrimitive(PrimitiveType_Char);
   20.19          if (!type)
   20.20              return false;
   20.21  
   20.22 -        type = types_->newArray(type, Type::DYNAMIC_ARRAY_SIZE, false);
   20.23 +        type = types_->newExternalArray(type);
   20.24          if (!type)
   20.25              return false;
   20.26  
   20.27 -        charArrayMap_ = ArrayMap::New(this, type);
   20.28 -        if (!charArrayMap_)
   20.29 +        externalCharArrayMap_ = ArrayMap::Attach(this, type);
   20.30 +        if (!externalCharArrayMap_)
   20.31              return false;
   20.32      }
   20.33  
   20.34 @@ -154,8 +154,8 @@
   20.35  {
   20.36      for (unsigned i = 0; i < MapKinds_Total; i++)
   20.37          visitor->visit(maps_[i].address());
   20.38 -    visitor->visit(charArrayMap_.address());
   20.39 -    visitor->visit(genericArrayMap_.address());
   20.40 +    visitor->visit(externalCharArrayMap_.address());
   20.41 +    visitor->visit(externalGenericArrayMap_.address());
   20.42      types()->accept(visitor);
   20.43  
   20.44      Local<Object> *local = lastLocalRoot_;
    21.1 --- a/src/Zone.h	Sun Sep 16 19:02:23 2012 -0700
    21.2 +++ b/src/Zone.h	Sun Sep 16 21:34:10 2012 -0700
    21.3 @@ -46,8 +46,8 @@
    21.4  
    21.5      // Map cache.
    21.6      Unbarriered<Map> maps_[MapKinds_Total];
    21.7 -    Unbarriered<ArrayMap> genericArrayMap_;
    21.8 -    Unbarriered<ArrayMap> charArrayMap_;
    21.9 +    Unbarriered<ArrayMap> externalGenericArrayMap_;
   21.10 +    Unbarriered<ArrayMap> externalCharArrayMap_;
   21.11  
   21.12      TypeManager *types_;
   21.13      StringPool *symbols_;
   21.14 @@ -93,11 +93,11 @@
   21.15      }
   21.16      Map *allocateMap(MapKind kind, size_t bytes, MapKind parent = MapKind_Meta);
   21.17  
   21.18 -    ArrayMap *genericArrayMap() {
   21.19 -        return genericArrayMap_;
   21.20 +    ArrayMap *externalGenericArrayMap() {
   21.21 +        return externalGenericArrayMap_;
   21.22      }
   21.23 -    ArrayMap *charArrayMap() {
   21.24 -        return charArrayMap_;
   21.25 +    ArrayMap *externalCharArrayMap() {
   21.26 +        return externalCharArrayMap_;
   21.27      }
   21.28  
   21.29      TypeManager *types() const {