Get string literals working again.
Get string literals working again.
1.1 --- a/src/Array.cpp Sat Dec 22 23:18:57 2012 -0800
1.2 +++ b/src/Array.cpp Mon Dec 24 02:49:20 2012 -0800
1.3 @@ -62,6 +62,8 @@
1.4 Array *
1.5 Array::NewRaw(Zone *zone, Handle<ArrayMap> map, unsigned nelements, Heap::Tenure tenure)
1.6 {
1.7 + assert(!map->type()->isFixedLength() || nelements == map->type()->fixedLength());
1.8 +
1.9 if (nelements > (INT_MAX / SizeForElement(map->type()))) {
1.10 zone->reportError(Message_ArraySizeTooBig);
1.11 return NULL;
1.12 @@ -209,16 +211,21 @@
1.13 }
1.14
1.15 Array *
1.16 -Array::NewString(Zone *zone, Handle<ArrayMap> map, Address buffer, size_t length, Heap::Tenure tenure)
1.17 +Array::NewString(Zone *zone, Handle<ArrayMap> map, char *buffer, size_t length, Heap::Tenure tenure)
1.18 {
1.19 assert(map->type()->isCharArray());
1.20
1.21 - Local<Array> array(zone, Array::New1D(zone, map, length, tenure));
1.22 + Local<Array> array(zone);
1.23 +
1.24 + if (map->type()->isFixedLength())
1.25 + array = Array::NewFixed(zone, map, tenure);
1.26 + else
1.27 + array = Array::New1D(zone, map, length + 1, tenure);
1.28 if (!array)
1.29 return NULL;
1.30
1.31 - assert(array->length() >= length);
1.32 - memcpy(array->chars(), buffer, length);
1.33 + assert(array->length() >= length + 1);
1.34 + memcpy(array->chars(), buffer, length + 1);
1.35 return array;
1.36 }
1.37
1.38 @@ -250,3 +257,90 @@
1.39 return array;
1.40 }
1.41
1.42 +static bool
1.43 +CopyArrayElements(Zone *zone, Handle<Type> contained, Handle<Array> dest, Handle<Array> source)
1.44 +{
1.45 + if (contained->isTraceable()) {
1.46 + if (contained->isStruct()) {
1.47 + assert(dest->type()->contained() == contained);
1.48 + assert(source->length() == dest->length());
1.49 +
1.50 + Local<Struct> left(zone);
1.51 + Local<Struct> right(zone);
1.52 + for (unsigned i = 0; i < source->length(); i++) {
1.53 + left = Struct::cast(dest->readObject(i));
1.54 + right = Struct::cast(source->readObject(i));
1.55 + if (!Struct::Copy(zone, left, right))
1.56 + return false;
1.57 + }
1.58 + } else {
1.59 + assert(dest->length() == source->length());
1.60 + for (unsigned i = 0; i < source->length(); i++)
1.61 + dest->writeObject(zone, i, source->readObject(i));
1.62 + }
1.63 + } else {
1.64 + assert(contained->pod() == dest->type()->contained()->pod());
1.65 + assert(contained->pod() == PrimitiveType_Char
1.66 + ? source->length() <= dest->length()
1.67 + : source->length() == dest->length());
1.68 +
1.69 + assert(dest->length());
1.70 + memcpy(dest->bytes(), source->bytes(), source->length() * Array::SizeForElement(dest->type()));
1.71 + }
1.72 + return true;
1.73 +}
1.74 +
1.75 +// Shallow copy an array. Fixed slots in the destination are copied from
1.76 +// the source, but otherwise, references are assigned.
1.77 +bool
1.78 +Array::ShallowCopy(Zone *zone, Handle<Array> dest, Handle<Array> source)
1.79 +{
1.80 +#if 0
1.81 + Local<Type> contained(zone, source->type()->contained());
1.82 + if (contained->isArray() && ArrayType::cast(contained)->isFixedLength()) {
1.83 + assert(dest->type()->contained()->isArray());
1.84 + assert(source->length() == dest->length());
1.85 +
1.86 + Local<Array> left(zone);
1.87 + Local<Array> right(zone);
1.88 + for (unsigned i = 0; i < source->length(); i++) {
1.89 + left = Array::cast(dest->readObject(i));
1.90 + right = Array::cast(source->readObject(i));
1.91 + if (!ShallowCopy(zone, left, right))
1.92 + return false;
1.93 + }
1.94 + return true;
1.95 + }
1.96 +
1.97 +#endif
1.98 + assert(false);
1.99 + return false;
1.100 +}
1.101 +
1.102 +Array *
1.103 +Array::DeepCopy(Zone *zone, Handle<Array> source, Heap::Tenure tenure)
1.104 +{
1.105 + Local<ArrayMap> map(zone, ArrayMap::cast(source->map()));
1.106 +
1.107 + Local<Array> dest(zone, Array::NewRaw(zone, map, source->length(), tenure));
1.108 + if (!dest)
1.109 + return NULL;
1.110 +
1.111 + Local<Type> contained(zone, source->type()->contained());
1.112 + if (contained->isArray()) {
1.113 + assert(false);
1.114 + Local<Array> sub(zone);
1.115 + for (size_t i = 0; i < source->length(); i++) {
1.116 + sub = Array::cast(source->readObject(i));
1.117 + sub = DeepCopy(zone, sub, tenure);
1.118 + if (!sub)
1.119 + return NULL;
1.120 + dest->writeObject(zone, i, sub);
1.121 + }
1.122 + } else {
1.123 + if (!CopyArrayElements(zone, contained, dest, source))
1.124 + return NULL;
1.125 + }
1.126 +
1.127 + return dest;
1.128 +}
2.1 --- a/src/Array.h Sat Dec 22 23:18:57 2012 -0800
2.2 +++ b/src/Array.h Mon Dec 24 02:49:20 2012 -0800
2.3 @@ -48,7 +48,7 @@
2.4
2.5 public:
2.6 static Array *NewFixed(Zone *zone, Handle<ArrayMap> map, Heap::Tenure = Heap::Tenure_Default);
2.7 - static Array *NewString(Zone *zone, Handle<ArrayMap> map, Address buffer, size_t length, Heap::Tenure = Heap::Tenure_Default);
2.8 + static Array *NewString(Zone *zone, Handle<ArrayMap> map, char *buffer, size_t length, Heap::Tenure = Heap::Tenure_Default);
2.9 static Array *NewSized(Zone *zone, Handle<ArrayMap> map, int sizes[MAX_ARRAY_DEPTH], Heap::Tenure = Heap::Tenure_Default);
2.10
2.11 static Array *New1D(Zone *zone, Handle<ArrayMap> map, uint32 elements, Heap::Tenure tenure = Heap::Tenure_Default);
2.12 @@ -61,6 +61,15 @@
2.13 unsigned length,
2.14 Heap::Tenure tenure = Heap::Tenure_Default);
2.15
2.16 + // Copies an array from one reference to another, obeying language semantics.
2.17 + static bool ShallowCopy(Zone *zone, Handle<Array> dest, Handle<Array> source);
2.18 +
2.19 + // Creates a full duplicate of an array, following all array references as if
2.20 + // they were fixed. Array references inside structs or objects use ShallowCopy
2.21 + // semantics, as this is only intended for duplicating array literals, which
2.22 + // cannot contain structs.
2.23 + static Array *DeepCopy(Zone *zone, Handle<Array> source, Heap::Tenure tenure);
2.24 +
2.25 uint32 length() {
2.26 return length_;
2.27 }
2.28 @@ -72,6 +81,7 @@
2.29 inline char *chars();
2.30 inline void *bytes();
2.31
2.32 + bool resize(Zone *zone, size_t newLength);
2.33
2.34 static inline size_t SizeForElement(ArrayType *type) {
2.35 if (type->contained()->isTraceable())
3.1 --- a/src/Interpreter.cpp Sat Dec 22 23:18:57 2012 -0800
3.2 +++ b/src/Interpreter.cpp Mon Dec 24 02:49:20 2012 -0800
3.3 @@ -82,69 +82,27 @@
3.4 return true;
3.5 }
3.6
3.7 -static bool CopyStruct(Zone *zone, Handle<Struct> left, Handle<Struct> right);
3.8 -
3.9 static bool
3.10 -ChangeArrayLength(Zone *zone, Handle<Array> source, Handle<Array> dest)
3.11 +DuplicateArray(Zone *zone, Handle<Array> src)
3.12 {
3.13 - return true;
3.14 -}
3.15 + Local<ArrayMap> map(zone, ArrayMap::cast(src->map()));
3.16 + Local<Array> dest(zone);
3.17
3.18 -// Even though this function can fail, we immediately bail out, so it doesn't
3.19 -// matter if we've leaving things unrooted.
3.20 -static bool
3.21 -CopyArray(Zone *zone, Handle<Array> dest, Handle<Array> source)
3.22 -{
3.23 - if (source->length() != dest->length()) {
3.24 - if (!ChangeArrayLength(zone, source, dest))
3.25 - return false;
3.26 + if (map->type()->isFixedLength()) {
3.27 + dest = Array::NewFixed(zone, map);
3.28 + } else {
3.29 + Type *type = map->type();
3.30 + int sizes[MAX_ARRAY_DEPTH];
3.31 + for (unsigned i = 0; i < map->type()->levels(); i++) {
3.32 + ArrayType *atype = ArrayType::cast(type);
3.33 + sizes[i] = atype->isFixedLength()
3.34 + ? atype->fixedLength()
3.35 + : 0;
3.36 + type = atype->contained();
3.37 + }
3.38 }
3.39
3.40 - Local<Type> contained(zone, source->type()->contained());
3.41 - if (contained->isArray() && ArrayType::cast(contained)->isFixedLength()) {
3.42 - assert(dest->type()->contained()->isArray());
3.43 - assert(source->length() == dest->length());
3.44 -
3.45 - Local<Array> left(zone);
3.46 - Local<Array> right(zone);
3.47 - for (unsigned i = 0; i < source->length(); i++) {
3.48 - left = Array::cast(dest->readObject(i));
3.49 - right = Array::cast(source->readObject(i));
3.50 - if (!CopyArray(zone, left, right))
3.51 - return false;
3.52 - }
3.53 - return true;
3.54 - }
3.55 -
3.56 - if (contained->isStruct()) {
3.57 - assert(dest->type()->contained() == contained);
3.58 - assert(source->length() == dest->length());
3.59 -
3.60 - Local<Struct> left(zone);
3.61 - Local<Struct> right(zone);
3.62 - for (unsigned i = 0; i < source->length(); i++) {
3.63 - left = Struct::cast(dest->readObject(i));
3.64 - right = Struct::cast(source->readObject(i));
3.65 - if (!CopyStruct(zone, left, right))
3.66 - return false;
3.67 - }
3.68 - return true;
3.69 - }
3.70 -
3.71 - if (contained->isTraceable()) {
3.72 - for (unsigned i = 0; i < source->length(); i++)
3.73 - dest->writeObject(zone, i, source->readObject(i));
3.74 - return true;
3.75 - }
3.76 -
3.77 - assert(contained->pod() == dest->type()->contained()->pod());
3.78 - assert(contained->pod() == PrimitiveType_Char
3.79 - ? source->length() <= dest->length()
3.80 - : source->length() == dest->length());
3.81 -
3.82 - assert(dest->length());
3.83 - memcpy(dest->bytes(), source->bytes(), source->length() * Array::SizeForElement(dest->type()));
3.84 - return true;
3.85 + Local<Array> dst(zone);
3.86 }
3.87
3.88 static void
3.89 @@ -269,49 +227,6 @@
3.90 StoreField(zone, obj, desc, v);
3.91 }
3.92
3.93 -// Even though this function can fail, we immediately bail out, so it doesn't
3.94 -// matter if we've leaving things unrooted.
3.95 -static bool
3.96 -CopyStruct(Zone *zone, Handle<Struct> left, Handle<Struct> right)
3.97 -{
3.98 - assert(left->map()->type() == right->map()->type());
3.99 -
3.100 - Local<StructType> type(zone, StructType::cast(left->map()->type()));
3.101 - Local<Struct> leftStruct(zone);
3.102 - Local<Struct> rightStruct(zone);
3.103 - Local<Array> leftArray(zone);
3.104 - Local<Array> rightArray(zone);
3.105 - for (unsigned i = 0; i < type->fields()->length(); i++) {
3.106 - Descriptor *desc = Descriptor::cast(type->fields()->at(i));
3.107 -
3.108 - LocalSlot rval;
3.109 - FetchField(right, desc, &rval);
3.110 -
3.111 - // If the field is a struct, we need to deep-copy.
3.112 - if (desc->type()->isStruct()) {
3.113 - LocalSlot lval;
3.114 -
3.115 - FetchField(left, desc, &lval);
3.116 - leftStruct = Struct::cast(lval.obj);
3.117 - rightStruct = Struct::cast(rval.obj);
3.118 - if (!CopyStruct(zone, leftStruct, rightStruct))
3.119 - return false;
3.120 - } else if (desc->type()->isArray()) {
3.121 - LocalSlot lval;
3.122 -
3.123 - FetchField(left, desc, &lval);
3.124 - leftArray = Array::cast(lval.obj);
3.125 - rightArray = Array::cast(rval.obj);
3.126 - if (!CopyArray(zone, leftArray, rightArray))
3.127 - return false;
3.128 - } else {
3.129 - StoreField(zone, left, desc, rval);
3.130 - }
3.131 - }
3.132 -
3.133 - return true;
3.134 -}
3.135 -
3.136 static bool
3.137 InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
3.138 int *result)
3.139 @@ -773,6 +688,15 @@
3.140 break;
3.141 }
3.142
3.143 +case OP_DUPARRAY:
3.144 +{
3.145 + Local<Array> src(zone, Array::cast(top.sp[-1].obj));
3.146 + top.sp[-1].obj = Array::DeepCopy(zone, src, Heap::Tenure_Default);
3.147 + if (!top.sp[-1].obj)
3.148 + goto error;
3.149 + break;
3.150 +}
3.151 +
3.152 case OP_NEWFIXED:
3.153 {
3.154 Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
3.155 @@ -905,7 +829,7 @@
3.156 // right, since in this case the result of the expression could be different.
3.157 Local<Array> left(zone, Array::cast(top.sp[-2].array));
3.158 Local<Array> right(zone, Array::cast(top.sp[-1].array));
3.159 - if (!CopyArray(zone, left, right))
3.160 + if (!Array::ShallowCopy(zone, left, right))
3.161 goto error;
3.162 top.sp--;
3.163 break;
3.164 @@ -1016,7 +940,7 @@
3.165 {
3.166 Local<Struct> left(zone, Struct::cast(top.sp[-2].obj));
3.167 Local<Struct> right(zone, Struct::cast(top.sp[-1].obj));
3.168 - if (!CopyStruct(zone, left, right))
3.169 + if (!Struct::Copy(zone, left, right))
3.170 goto error;
3.171 top.sp[-2].obj = top.sp[-1].obj;
3.172 top.sp--;
4.1 --- a/src/ObjectVisitor.h Sat Dec 22 23:18:57 2012 -0800
4.2 +++ b/src/ObjectVisitor.h Mon Dec 24 02:49:20 2012 -0800
4.3 @@ -142,7 +142,7 @@
4.4 }
4.5
4.6 size_t iterateArray(Array *array, ArrayMap *map) {
4.7 - if (!map->type()->fixedLength() || map->type()->contained()->isTraceable())
4.8 + if (!map->type()->hasInlineElements())
4.9 visitField(array, Array::offsetOfElements());
4.10 return array->objSize(map);
4.11 }
5.1 --- a/src/Opcodes.cpp Sat Dec 22 23:18:57 2012 -0800
5.2 +++ b/src/Opcodes.cpp Mon Dec 24 02:49:20 2012 -0800
5.3 @@ -210,6 +210,7 @@
5.4 case OP_SIZEOF:
5.5 case OP_PUBLIC:
5.6 case OP_LEAVELOOP:
5.7 + case OP_DUPARRAY:
5.8 break;
5.9
5.10 case OP_ENTERLOOP:
6.1 --- a/src/Opcodes.tbl Sat Dec 22 23:18:57 2012 -0800
6.2 +++ b/src/Opcodes.tbl Mon Dec 24 02:49:20 2012 -0800
6.3 @@ -100,6 +100,9 @@
6.4 OPDEF(OP_NEWEMPTY, "newempty", 6, 0, 1)
6.5 OPDEF(OP_NEWSIZED, "newsized", 6, -1, 1)
6.6
6.7 +// Creates a duplicate copy of an array.
6.8 +OPDEF(OP_DUPARRAY, "duparray", 1, 1, 1)
6.9 +
6.10 // Performs an array-to-array assignment.
6.11 // Left = pop()
6.12 // Right = pop()
7.1 --- a/src/Structures.cpp Sat Dec 22 23:18:57 2012 -0800
7.2 +++ b/src/Structures.cpp Mon Dec 24 02:49:20 2012 -0800
7.3 @@ -37,8 +37,13 @@
7.4 *offset = size_;
7.5
7.6 if (!type->isTraceable()) {
7.7 - // For now, assume the size of primitives is 4-byte.
7.8 - assert(type->isInt32() || type->isFloat());
7.9 + // For now, assume the alignment of all primitive storage is 4 bytes,
7.10 + // and that all need <= 4 bytes of storage.
7.11 + assert(type->isInt32() ||
7.12 + type->isFloat() ||
7.13 + type->isBool() ||
7.14 + type->isChar() ||
7.15 + type->isEnum());
7.16 size_ += 4;
7.17 return true;
7.18 }
7.19 @@ -147,3 +152,50 @@
7.20 return obj;
7.21 }
7.22
7.23 +bool
7.24 +Struct::Copy(Zone *zone, Handle<Struct> left, Handle<Struct> right)
7.25 +{
7.26 + assert(left->map()->type() == right->map()->type());
7.27 +
7.28 + Local<StructType> type(zone, StructType::cast(left->map()->type()));
7.29 + Local<Struct> leftStruct(zone);
7.30 + Local<Struct> rightStruct(zone);
7.31 + Local<Array> leftArray(zone);
7.32 + Local<Array> rightArray(zone);
7.33 + for (unsigned i = 0; i < type->fields()->length(); i++) {
7.34 + Descriptor *desc = Descriptor::cast(type->fields()->at(i));
7.35 +
7.36 + // If the field is a struct, we need to deep-copy.
7.37 + if (desc->type()->isStruct()) {
7.38 + leftStruct = Struct::cast(left->get<Object *>(desc));
7.39 + rightStruct = Struct::cast(right->get<Object *>(desc));
7.40 + if (!Struct::Copy(zone, leftStruct, rightStruct))
7.41 + return false;
7.42 + } else if (desc->type()->isArray()) {
7.43 + leftArray = Array::cast(left->get<Object *>(desc));
7.44 + rightArray = Array::cast(right->get<Object *>(desc));
7.45 + if (!Array::ShallowCopy(zone, leftArray, rightArray))
7.46 + return false;
7.47 + } else if (desc->type()->isTraceable()) {
7.48 + Object *obj = right->get<Object *>(desc);
7.49 + left->set(zone, desc, obj);
7.50 + } else {
7.51 + switch (desc->type()->pod()) {
7.52 + case PrimitiveType_Int32:
7.53 + case PrimitiveType_Char:
7.54 + case PrimitiveType_Bool:
7.55 + left->set(desc, right->get<int>(desc));
7.56 + break;
7.57 +
7.58 + case PrimitiveType_Float:
7.59 + left->set(desc, right->get<float>(desc));
7.60 + break;
7.61 +
7.62 + default:
7.63 + assert(false);
7.64 + }
7.65 + }
7.66 + }
7.67 +
7.68 + return true;
7.69 +}
7.70 \ No newline at end of file
8.1 --- a/src/Structures.h Sat Dec 22 23:18:57 2012 -0800
8.2 +++ b/src/Structures.h Mon Dec 24 02:49:20 2012 -0800
8.3 @@ -158,6 +158,8 @@
8.4 public:
8.5 static Struct *New(Zone *zone, Handle<StructMap> map, Heap::Tenure tenure = Heap::Tenure_Default);
8.6
8.7 + static bool Copy(Zone *zone, Handle<Struct> dest, Handle<Struct> src);
8.8 +
8.9 size_t objSize() {
8.10 return sizeof(Struct) + map()->structureSize();
8.11 }
8.12 @@ -169,11 +171,12 @@
8.13 return reinterpret_cast<Address>(this) + offsetOfSlotOffset(desc->offset());
8.14 }
8.15
8.16 - // This must NOT be used with any Object * type!
8.17 template <typename T> T get(Descriptor *desc) {
8.18 return *reinterpret_cast<T *>(ref(desc));
8.19 }
8.20
8.21 + // This must NOT be used with any Object * type!
8.22 + // :TODO: prevent with type system
8.23 template <typename T> void set(Descriptor *desc, const T &t) {
8.24 *reinterpret_cast<T *>(ref(desc)) = t;
8.25 }
9.1 --- a/src/TypeManager.cpp Sat Dec 22 23:18:57 2012 -0800
9.2 +++ b/src/TypeManager.cpp Mon Dec 24 02:49:20 2012 -0800
9.3 @@ -53,6 +53,8 @@
9.4 return false;
9.5 if ((primitiveTypes_[PrimitiveType_Bool] = Type::NewPrimitive(zone_, PrimitiveType_Bool)) == NULL)
9.6 return false;
9.7 + if ((primitiveTypes_[PrimitiveType_String] = Type::NewPrimitive(zone_, PrimitiveType_String)) == NULL)
9.8 + return false;
9.9
9.10 Local<Type> type(zone_);
9.11 for (unsigned i = 0; i < PrimitiveTypes_Total; i++) {
10.1 --- a/src/Types.h Sat Dec 22 23:18:57 2012 -0800
10.2 +++ b/src/Types.h Mon Dec 24 02:49:20 2012 -0800
10.3 @@ -57,6 +57,9 @@
10.4 // on 64-bit systems), and does not exist in language semantics.
10.5 PrimitiveType_Native,
10.6
10.7 + // Internal string object.
10.8 + PrimitiveType_String,
10.9 +
10.10 PrimitiveTypes_Total
10.11 };
10.12
10.13 @@ -144,7 +147,7 @@
10.14 return primitive_;
10.15 }
10.16 bool isPod() {
10.17 - return isPrimitive() || isEnum() || isUnchecked();
10.18 + return (isPrimitive() && !isString()) || isEnum() || isUnchecked();
10.19 }
10.20 PrimitiveType pod() {
10.21 assert(isPod());
10.22 @@ -169,11 +172,18 @@
10.23 bool isBool() {
10.24 return isPrimitive() && primitive() == PrimitiveType_Bool;
10.25 }
10.26 + bool isString() {
10.27 + return isPrimitive() && primitive() == PrimitiveType_String;
10.28 + }
10.29 bool isExternalArray() {
10.30 return kind() == EXTERNAL_ARRAY;
10.31 }
10.32 bool isTraceable() {
10.33 - return !isPrimitive();
10.34 + return (isPrimitive() && primitive() == PrimitiveType_String) ||
10.35 + isReference() ||
10.36 + isArray() ||
10.37 + isStruct() ||
10.38 + isFunction();
10.39 }
10.40 bool isConst() {
10.41 assert(isPrimitive() ||
10.42 @@ -250,7 +260,6 @@
10.43 static ArrayType *NewExternal(Zone *zone, Handle<Type> contained);
10.44
10.45 Type *innermost() {
10.46 - assert(isArray());
10.47 Type *temp = contained();
10.48 while (temp->isArray())
10.49 temp = ArrayType::cast(temp)->contained();
10.50 @@ -261,7 +270,6 @@
10.51 return contained_;
10.52 }
10.53 bool isFixedLength() {
10.54 - assert(isArray());
10.55 return elements_ > 0;
10.56 }
10.57 bool isCharArray() {
10.58 @@ -273,12 +281,9 @@
10.59 return elements_;
10.60 }
10.61 unsigned levels() {
10.62 - assert(isArray());
10.63 return levels_;
10.64 }
10.65 bool hasInlineElements() {
10.66 - assert(isArray());
10.67 -
10.68 // We don't allocate traceable elements inline, since there's no
10.69 // point to the optimization; we're going to be allocating lots of
10.70 // objects anyway (in theory).
11.1 --- a/src/compiler/AST.h Sat Dec 22 23:18:57 2012 -0800
11.2 +++ b/src/compiler/AST.h Mon Dec 24 02:49:20 2012 -0800
11.3 @@ -332,18 +332,18 @@
11.4
11.5 class StringLiteral : public Expression
11.6 {
11.7 - ScopedRoot<ByteArray> string_;
11.8 + ScopedRoot<String> string_;
11.9
11.10 public:
11.11 - StringLiteral(const SourcePosition &pos, ByteArray *array)
11.12 + StringLiteral(const SourcePosition &pos, String *string)
11.13 : Expression(pos),
11.14 - string_(array)
11.15 + string_(string)
11.16 {
11.17 }
11.18
11.19 DECLARE_NODE(StringLiteral);
11.20
11.21 - ByteArray *string() const {
11.22 + String *string() const {
11.23 return string_;
11.24 }
11.25 };
12.1 --- a/src/compiler/BytecodeEmitter.h Sat Dec 22 23:18:57 2012 -0800
12.2 +++ b/src/compiler/BytecodeEmitter.h Mon Dec 24 02:49:20 2012 -0800
12.3 @@ -188,9 +188,10 @@
12.4 maxStackDepth_ = oopMap_.length();
12.5 }
12.6 void writeObject(Object *obj) {
12.7 + assert(obj);
12.8 +
12.9 writeUint32(objects_.length());
12.10 - ScopedRoot<Object> root(obj);
12.11 - if (!objects_.append(root))
12.12 + if (!objects_.append(obj))
12.13 oom_ = true;
12.14 }
12.15
12.16 @@ -528,11 +529,17 @@
12.17 }
12.18 }
12.19 void object(Handle<Object> obj) {
12.20 + assert(obj);
12.21 +
12.22 ensure(OP_OBJECT_LENGTH);
12.23 writeOp(OP_OBJECT);
12.24 writeObject(obj);
12.25 markOop(1);
12.26 }
12.27 + void duparray() {
12.28 + singleByteOp(OP_DUPARRAY);
12.29 + markOop(1);
12.30 + }
12.31 void copyarray() {
12.32 singleByteOp(OP_COPYARRAY);
12.33 markOop(1);
13.1 --- a/src/compiler/HIR.cpp Sat Dec 22 23:18:57 2012 -0800
13.2 +++ b/src/compiler/HIR.cpp Mon Dec 24 02:49:20 2012 -0800
13.3 @@ -19,6 +19,7 @@
13.4 #include "AST.h"
13.5 #include "HIR.h"
13.6 #include "BytecodeEmitter.h"
13.7 +#include "../Strings.h"
13.8 #include "../Heap-inl.h"
13.9 #include "../Handles-inl.h"
13.10
13.11 @@ -39,6 +40,7 @@
13.12
13.13 void visitFloat(HFloat *hir);
13.14 void visitInteger(HInteger *hir);
13.15 + void visitArray(HArray *hir);
13.16 void visitCall(HCall *call);
13.17 void visitStore(HStore *store);
13.18 void visitBinary(HBinary *binary);
13.19 @@ -69,6 +71,18 @@
13.20 }
13.21
13.22 void
13.23 +HIRTranslator::visitArray(HArray *hir)
13.24 +{
13.25 + __ object(hir->array());
13.26 +
13.27 + if (!hir->type()->isConst()) {
13.28 + // If the type isn't const, we have to assume a consumer may modify
13.29 + // the array, and therefore we have to duplicate it here.
13.30 + __ duparray();
13.31 + }
13.32 +}
13.33 +
13.34 +void
13.35 HIRTranslator::visitCall(HCall *call)
13.36 {
13.37 Local<FunctionType> fun(zone_, FunctionType::cast(call->callee()->type()));
14.1 --- a/src/compiler/HIR.h Sat Dec 22 23:18:57 2012 -0800
14.2 +++ b/src/compiler/HIR.h Mon Dec 24 02:49:20 2012 -0800
14.3 @@ -29,6 +29,8 @@
14.4 _(Call) \
14.5 _(Integer) \
14.6 _(Float) \
14.7 + _(String) \
14.8 + _(Array) \
14.9 _(Store) \
14.10 _(ToRef) \
14.11 /* Special LValue types */ \
14.12 @@ -48,6 +50,7 @@
14.13 class HIRVisitor;
14.14 class AstNode;
14.15 class HLValue;
14.16 +class Array;
14.17
14.18 class HIR : public PoolObject
14.19 {
14.20 @@ -142,6 +145,42 @@
14.21 int value_;
14.22 };
14.23
14.24 +class HString : public HIR
14.25 +{
14.26 + public:
14.27 + HString(AstNode *node, Type *type, String *string)
14.28 + : HIR(node, type),
14.29 + string_(string)
14.30 + {
14.31 + }
14.32 +
14.33 + DEFINE_HIR(String);
14.34 + Handle<String> string() const {
14.35 + return string_;
14.36 + }
14.37 +
14.38 + private:
14.39 + ScopedRoot<String> string_;
14.40 +};
14.41 +
14.42 +class HArray : public HIR
14.43 +{
14.44 + public:
14.45 + HArray(AstNode *node, Type *type, Array *array)
14.46 + : HIR(node, type),
14.47 + array_(array)
14.48 + {
14.49 + }
14.50 +
14.51 + DEFINE_HIR(Array);
14.52 + Handle<Array> array() const {
14.53 + return array_;
14.54 + }
14.55 +
14.56 + private:
14.57 + ScopedRoot<Array> array_;
14.58 +};
14.59 +
14.60 class HConvert : public HIR
14.61 {
14.62 public:
15.1 --- a/src/compiler/Parser.cpp Sat Dec 22 23:18:57 2012 -0800
15.2 +++ b/src/compiler/Parser.cpp Mon Dec 24 02:49:20 2012 -0800
15.3 @@ -122,11 +122,8 @@
15.4 case TOK_STRING_LITERAL:
15.5 {
15.6 scanner_.scan();
15.7 - Local<ByteArray> array(zone_, ByteArray::New(zone_, scanner_.literal_length() + 1));
15.8 - if (!array)
15.9 - return NULL;
15.10 - memcpy(array->raw(), scanner_.literal(), scanner_.literal_length() + 1);
15.11 - return new (pool_) StringLiteral(scanner_.begin(), array);
15.12 + Local<String> string(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
15.13 + return new (pool_) StringLiteral(scanner_.begin(), string);
15.14 }
15.15
15.16 default:
16.1 --- a/src/compiler/SemanticAnalysis.cpp Sat Dec 22 23:18:57 2012 -0800
16.2 +++ b/src/compiler/SemanticAnalysis.cpp Mon Dec 24 02:49:20 2012 -0800
16.3 @@ -429,31 +429,31 @@
16.4 PoolScope poolScope(zone_->pool());
16.5 RootScope rootScope(zone_);
16.6
16.7 + Local<Type> type(zone_, node->sym()->type());
16.8 +
16.9 if (node->initialization()) {
16.10 HIR *hir = NULL;
16.11
16.12 if ((hir = eval(node->initialization())) == NULL)
16.13 return;
16.14 - if ((hir = coerce(hir, node->sym()->type(), Coerce_Assign)) == NULL)
16.15 + if ((hir = coerce(hir, type, Coerce_Assign)) == NULL)
16.16 return;
16.17
16.18 discharge(hir);
16.19 } else {
16.20 - if (node->sym()->type()->isInt32() ||
16.21 - node->sym()->type()->isEnum() ||
16.22 - node->sym()->type()->isChar() ||
16.23 - node->sym()->type()->isBool())
16.24 + if (type->isInt32() || type->isEnum() ||
16.25 + type->isChar() || type->isBool())
16.26 {
16.27 __ int_(0);
16.28 - } else if (node->sym()->type()->isFloat()) {
16.29 + } else if (type->isFloat()) {
16.30 __ float_(0);
16.31 - } else if (node->sym()->type()->isArray()) {
16.32 - Local<ArrayType> type(zone_, ArrayType::cast(node->sym()->type()));
16.33 - Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
16.34 + } else if (type->isArray()) {
16.35 + Local<ArrayType> atype(zone_, ArrayType::cast(type));
16.36 + Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, atype));
16.37 if (!map)
16.38 return;
16.39
16.40 - if (type->isFixedLength()) {
16.41 + if (atype->isFixedLength()) {
16.42 __ newarray(OP_NEWFIXED, map, InferTenure(node->sym()));
16.43 } else if (node->dims()) {
16.44 assert(false);
16.45 @@ -461,11 +461,15 @@
16.46 } else {
16.47 __ newarray(OP_NEWEMPTY, map, InferTenure(node->sym()));
16.48 }
16.49 + } else {
16.50 + assert(false);
16.51 }
16.52 }
16.53
16.54 - if (!__ allocate(node->sym()))
16.55 - return;
16.56 + if (node->sym()->scope()->kind() != Scope::GLOBAL) {
16.57 + if (!__ allocate(node->sym()))
16.58 + return;
16.59 + }
16.60
16.61 set(node->sym());
16.62 __ pop();
16.63 @@ -613,6 +617,13 @@
16.64 }
16.65
16.66 void
16.67 +SemanticAnalysis::visitStringLiteral(StringLiteral *node)
16.68 +{
16.69 + Type *type = zone_->types()->getPrimitive(PrimitiveType_String);
16.70 + hir_ = new (pool_) HString(node, type, node->string());
16.71 +}
16.72 +
16.73 +void
16.74 SemanticAnalysis::visitCallExpression(CallExpression *node)
16.75 {
16.76 HIR *callee = eval(node->callee());
16.77 @@ -804,15 +815,55 @@
16.78 return left->type();
16.79 }
16.80
16.81 -bool
16.82 +HIR *
16.83 SemanticAnalysis::typeCheckArray(const SourcePosition &pos,
16.84 - Handle<Type> argGiven,
16.85 + HIR *from,
16.86 Handle<Type> argActual,
16.87 CoercionKind kind)
16.88 {
16.89 + Local<Type> argGiven(zone_, from->type());
16.90 +
16.91 + // Special case: if we receive a string literal, and this is a char array,
16.92 + // we allow a coercion.
16.93 + if (from->isString() &&
16.94 + argGiven->isString() &&
16.95 + argActual->isArray() &&
16.96 + ArrayType::cast(argActual)->isCharArray())
16.97 + {
16.98 + HString *hir = from->toString();
16.99 + Local<ArrayType> actual(zone_, ArrayType::cast(argActual));
16.100 +
16.101 + // If assigning or returning, and the desired type is fixed length,
16.102 + // make sure there is enough room.
16.103 + if ((kind == Coerce_Return || kind == Coerce_Assign) && actual->isFixedLength()) {
16.104 + if (hir->string()->length() + 1 > actual->fixedLength()) {
16.105 + cc_.reportError(pos, Message_ArrayAssignmentTooBig);
16.106 + return NULL;
16.107 + }
16.108 + }
16.109 +
16.110 + // Transform the string literal into an array literal. We give it the
16.111 + // type of the left-hand side. The constness of the destination type
16.112 + // will determine whether HArray duplicates it or not.
16.113 + Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, actual));
16.114 + if (!map)
16.115 + return NULL;
16.116 +
16.117 + Local<Array> array(zone_);
16.118 + array = Array::NewString(zone_,
16.119 + map,
16.120 + hir->string()->chars(),
16.121 + hir->string()->length(),
16.122 + Heap::Tenure_Old);
16.123 + if (!array)
16.124 + return NULL;
16.125 +
16.126 + return new (pool_) HArray(hir->node(), actual, array);
16.127 + }
16.128 +
16.129 if (!argGiven->isArray()) {
16.130 cc_.reportError(pos, Message_ExpectedArray);
16.131 - return false;
16.132 + return NULL;
16.133 }
16.134
16.135 Local<ArrayType> actual(zone_, ArrayType::cast(argActual));
16.136 @@ -820,7 +871,7 @@
16.137
16.138 if (actual->levels() != given->levels()) {
16.139 cc_.reportError(pos, Message_ArrayDimensionsMismatch);
16.140 - return false;
16.141 + return NULL;
16.142 }
16.143
16.144 unsigned level = 1;
16.145 @@ -829,19 +880,19 @@
16.146 if (kind == Coerce_Return || kind == Coerce_Assign) {
16.147 if (!given->isFixedLength()) {
16.148 cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
16.149 - return false;
16.150 + return NULL;
16.151 }
16.152
16.153 if (actual->isCharArray()) {
16.154 // String assignment can have a truncated |given|.
16.155 if (given->fixedLength() > actual->fixedLength()) {
16.156 cc_.reportError(pos, Message_ArrayAssignmentTooBig);
16.157 - return false;
16.158 + return NULL;
16.159 }
16.160 } else {
16.161 if (given->fixedLength() != actual->fixedLength()) {
16.162 cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
16.163 - return false;
16.164 + return NULL;
16.165 }
16.166 }
16.167 }
16.168 @@ -863,7 +914,7 @@
16.169 // Now |x[0]| contains a 3-length array.
16.170 if (level > 1) {
16.171 cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
16.172 - return false;
16.173 + return NULL;
16.174 }
16.175 }
16.176
16.177 @@ -882,7 +933,7 @@
16.178 return false;
16.179 }
16.180
16.181 - return true;
16.182 + return from;
16.183 }
16.184
16.185 HIR *
16.186 @@ -897,21 +948,18 @@
16.187 HIR *
16.188 SemanticAnalysis::coerce(HIR *hir, Handle<Type> to, CoercionKind kind)
16.189 {
16.190 - Handle<Type> from = hir->type();
16.191 + Local<Type> from(zone_, hir->type());
16.192
16.193 if (from->isInt32() && to->isFloat())
16.194 return new (pool_) HConvert(hir->node(), to, OP_CVT_I2F, hir);
16.195 if (from->isInt32() && to->isBool())
16.196 return new (pool_) HConvert(hir->node(), to, OP_CVT_I2B, hir);
16.197
16.198 - if (to->isEnum() && from != to)
16.199 + if (to->isEnum() && *from != to)
16.200 return typeFailure(hir->node()->pos(), from, to);
16.201
16.202 - if (to->isArray()) {
16.203 - if (!typeCheckArray(SourcePosition(), from, to, kind))
16.204 - return NULL;
16.205 - return hir;
16.206 - }
16.207 + if (to->isArray())
16.208 + return typeCheckArray(SourcePosition(), hir, to, kind);
16.209
16.210 return hir;
16.211 }
16.212 @@ -1003,7 +1051,7 @@
16.213 hir = eval(expr->toUnaryExpression()->expression());
16.214 if (!hir)
16.215 return;
16.216 - if ((hir = coerce(hir, boolType, Coerce_Assign)) == NULL)
16.217 + if ((hir = coerce(hir, boolType, Coerce_Arg)) == NULL)
16.218 return;
16.219
16.220 discharge(hir);
16.221 @@ -1033,7 +1081,7 @@
16.222 HIR *hir = binary(bin, bin->token(), left, right);
16.223 if (!hir)
16.224 return;
16.225 - if ((hir = coerce(hir, boolType, Coerce_Assign)) == NULL)
16.226 + if ((hir = coerce(hir, boolType, Coerce_Arg)) == NULL)
16.227 return;
16.228
16.229 discharge(hir);
17.1 --- a/src/compiler/SemanticAnalysis.h Sat Dec 22 23:18:57 2012 -0800
17.2 +++ b/src/compiler/SemanticAnalysis.h Mon Dec 24 02:49:20 2012 -0800
17.3 @@ -64,13 +64,13 @@
17.4 void visitIfStatement(IfStatement *node);
17.5 void visitIndexExpression(IndexExpression *node);
17.6 void visitIncDecExpression(IncDecExpression *node);
17.7 + void visitStringLiteral(StringLiteral *node);
17.8 #if 0
17.9 void visitFunctionTypeStatement(FunctionTypeStatement *node);
17.10 void visitImportStatement(ImportStatement *node);
17.11 void visitStructureStatement(StructureStatement *node);
17.12 void visitSwitchStatement(SwitchStatement *node);
17.13
17.14 - void visitStringLiteral(StringLiteral *node);
17.15 void visitUnaryExpression(UnaryExpression *node);
17.16 void visitTernaryExpression(TernaryExpression *node);
17.17 void visitBooleanLiteral(BooleanLiteral *node);
17.18 @@ -180,8 +180,8 @@
17.19 void discharge(HIR *hir);
17.20 HIR *typeFailure(const SourcePosition &pos, Handle<Type> from, Handle<Type> to);
17.21
17.22 - bool typeCheckArray(const SourcePosition &pos,
17.23 - Handle<Type> argGiven,
17.24 + HIR *typeCheckArray(const SourcePosition &pos,
17.25 + HIR *from,
17.26 Handle<Type> argActual,
17.27 CoercionKind kind);
17.28
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
18.2 +++ b/tests/basic/string-lit-1.out Mon Dec 24 02:49:20 2012 -0800
18.3 @@ -0,0 +1,1 @@
18.4 +101121
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
19.2 +++ b/tests/basic/string-lit-1.sp Mon Dec 24 02:49:20 2012 -0800
19.3 @@ -0,0 +1,9 @@
19.4 +native PrintNum(num);
19.5 +
19.6 +public main()
19.7 +{
19.8 + new char:str1[] = "hello";
19.9 + new char:str2[4] = "bye";
19.10 + PrintNum(str1[1]);
19.11 + PrintNum(str2[1]);
19.12 +}