# HG changeset patch # User David Anderson # Date 1356394153 28800 # Node ID 072f1114ea5ddc43db6da7cae6660cab220c8fbb # Parent 43287eef2fffcaa1201a65763720361d34eaae56 Re-implement array assignment. diff -r 43287eef2fff -r 072f1114ea5d src/Array.cpp --- a/src/Array.cpp Mon Dec 24 02:56:02 2012 -0800 +++ b/src/Array.cpp Mon Dec 24 16:09:13 2012 -0800 @@ -273,6 +273,18 @@ if (!Struct::Copy(zone, left, right)) return false; } + } else if (contained->isArray() && ArrayType::cast(contained)->isFixedLength()) { + assert(ArrayType::cast(source->type())->fixedLength() == + ArrayType::cast(contained)->fixedLength()); + + Local left(zone); + Local right(zone); + for (unsigned i = 0; i < source->length(); i++) { + left = Array::cast(dest->readObject(i)); + right = Array::cast(source->readObject(i)); + if (!Array::ShallowCopy(zone, left, right)) + return false; + } } else { assert(dest->length() == source->length()); for (unsigned i = 0; i < source->length(); i++) @@ -295,26 +307,9 @@ bool Array::ShallowCopy(Zone *zone, Handle dest, Handle source) { -#if 0 - Local contained(zone, source->type()->contained()); - if (contained->isArray() && ArrayType::cast(contained)->isFixedLength()) { - assert(dest->type()->contained()->isArray()); - assert(source->length() == dest->length()); + Local contained(zone, dest->type()->contained()); - Local left(zone); - Local right(zone); - for (unsigned i = 0; i < source->length(); i++) { - left = Array::cast(dest->readObject(i)); - right = Array::cast(source->readObject(i)); - if (!ShallowCopy(zone, left, right)) - return false; - } - return true; - } - -#endif - assert(false); - return false; + return CopyArrayElements(zone, contained, dest, source); } Array * diff -r 43287eef2fff -r 072f1114ea5d src/Interpreter.cpp --- a/src/Interpreter.cpp Mon Dec 24 02:56:02 2012 -0800 +++ b/src/Interpreter.cpp Mon Dec 24 16:09:13 2012 -0800 @@ -82,29 +82,6 @@ return true; } -static bool -DuplicateArray(Zone *zone, Handle src) -{ - Local map(zone, ArrayMap::cast(src->map())); - Local dest(zone); - - if (map->type()->isFixedLength()) { - dest = Array::NewFixed(zone, map); - } else { - Type *type = map->type(); - int sizes[MAX_ARRAY_DEPTH]; - for (unsigned i = 0; i < map->type()->levels(); i++) { - ArrayType *atype = ArrayType::cast(type); - sizes[i] = atype->isFixedLength() - ? atype->fixedLength() - : 0; - type = atype->contained(); - } - } - - Local dst(zone); -} - static void GetElement(Array *array, int index, LocalSlot *vp) { diff -r 43287eef2fff -r 072f1114ea5d src/Opcodes.tbl --- a/src/Opcodes.tbl Mon Dec 24 02:56:02 2012 -0800 +++ b/src/Opcodes.tbl Mon Dec 24 16:09:13 2012 -0800 @@ -100,7 +100,8 @@ OPDEF(OP_NEWEMPTY, "newempty", 6, 0, 1) OPDEF(OP_NEWSIZED, "newsized", 6, -1, 1) -// Creates a duplicate copy of an array. +// Creates a duplicate copy of an array. This is a deep clone, rather than +// COPYARRAY, which is shallow. OPDEF(OP_DUPARRAY, "duparray", 1, 1, 1) // Performs an array-to-array assignment. @@ -108,7 +109,7 @@ // Right = pop() // copy(Left, Right) // push(Left) -OPDEF(OP_COPYARRAY, "arraycopy", 1, 2, 1) +OPDEF(OP_COPYARRAY, "copyarray", 1, 2, 1) // Reads or writes an integer element to an unsafe array. // index = pop() diff -r 43287eef2fff -r 072f1114ea5d src/Types.cpp --- a/src/Types.cpp Mon Dec 24 02:56:02 2012 -0800 +++ b/src/Types.cpp Mon Dec 24 16:09:13 2012 -0800 @@ -135,86 +135,6 @@ return type; } -#if 0 -Type * -Type::NewNative(Zone *zone, Handle returnType, Handle parameters, - Handle defaults, bool variadic) -{ - Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); - if (!type) - return NULL; - - type->kind_ = NATIVE; - type->contained_ = NULL; - type->fields_ = NULL; - type->newMap_ = NULL; - type->returnType_ = returnType; - type->parameters_ = parameters; - type->defaults_ = defaults; - type->variadicNative_ = variadic; - return type; -} -#endif - -bool -Type::Compare(Type *left, Type *right) -{ - if (left == right) - return true; - - if (left->kind() != right->kind()) - return false; - - switch (left->kind()) { - case Type::PRIMITIVE: - return left->primitive() == right->primitive(); - - case Type::ARRAY: - { - ArrayType *aleft = ArrayType::cast(left); - ArrayType *aright = ArrayType::cast(right); - if (aleft->levels() != aright->levels()) - return false; - if (aleft->isFixedLength() != aright->isFixedLength()) - return false; - if (aleft->isFixedLength() && aleft->fixedLength() != aright->fixedLength()) - return false; - return Compare(aleft->contained(), aright->contained()); - } - - case Type::FUNCTION: - { - FunctionType *fleft = FunctionType::cast(left); - FunctionType *fright = FunctionType::cast(right); - if (!Compare(fleft->returnType(), fright->returnType())) - return false; - if (fleft->parameters()->length() != fright->parameters()->length()) - return false; - if (fleft->isNative() != fright->isNative()) - return false; - if (fleft->isNative() && (fleft->isNativeVariadic() != fright->isNativeVariadic())) - return false; - for (unsigned i = 0; i < fleft->parameters()->length(); i++) { - Type *leftparam = fleft->parameterAt(i); - Type *rightparam = fright->parameterAt(i); - if (!Compare(leftparam, rightparam)) - return false; - } - return true; - } - - case Type::ENUM: - return false; - - case Type::VOID: - return true; - - default: - assert(left->kind() == Type::REFERENCE); - return Compare(ReferenceType::cast(left)->contained(), ReferenceType::cast(right)->contained()); - } -} - StructType * StructType::New(Zone *zone, Handle name, Handle fields) { diff -r 43287eef2fff -r 072f1114ea5d src/Types.h --- a/src/Types.h Mon Dec 24 02:56:02 2012 -0800 +++ b/src/Types.h Mon Dec 24 16:09:13 2012 -0800 @@ -113,8 +113,6 @@ static Type *NewPrimitive(Zone *zone, PrimitiveType type); static Type *NewString(Zone *zone); - static bool Compare(Type *left, Type *right); - static Type *cast(Object *obj) { assert(!obj || obj->is(MapKind_Type) || diff -r 43287eef2fff -r 072f1114ea5d src/compiler/HIR.cpp --- a/src/compiler/HIR.cpp Mon Dec 24 02:56:02 2012 -0800 +++ b/src/compiler/HIR.cpp Mon Dec 24 16:09:13 2012 -0800 @@ -75,11 +75,8 @@ { __ object(hir->array()); - if (!hir->type()->isConst()) { - // If the type isn't const, we have to assume a consumer may modify - // the array, and therefore we have to duplicate it here. + if (hir->duplicate()) __ duparray(); - } } void @@ -355,16 +352,30 @@ HIRTranslator::visitStore(HStore *store) { store->lval()->bind(this, emitter_); + if (store->kind() == TOK_ASSIGN) { - store->rval()->accept(this); + // Fixed-length arrays and structs have copy semantics. + Local type(zone_, store->lval()->type()); + if (type->isArray() && ArrayType::cast(type)->isFixedLength()) { + store->lval()->load(emitter_); + store->rval()->accept(this); + __ copyarray(); + } else if (type->isStruct()) { + store->lval()->load(emitter_); + store->rval()->accept(this); + __ copystruct(); + } else { + store->rval()->accept(this); + store->lval()->store(emitter_); + } } else { // Advanced case: dup the ref, load, op, store. store->lval()->hold(emitter_); store->lval()->load(emitter_); store->rval()->accept(this); __ binary(TokenToOpcode(store->kind())); + store->lval()->store(emitter_); } - store->lval()->store(emitter_); } void diff -r 43287eef2fff -r 072f1114ea5d src/compiler/HIR.h --- a/src/compiler/HIR.h Mon Dec 24 02:56:02 2012 -0800 +++ b/src/compiler/HIR.h Mon Dec 24 16:09:13 2012 -0800 @@ -166,9 +166,10 @@ class HArray : public HIR { public: - HArray(AstNode *node, Type *type, Array *array) + HArray(AstNode *node, Type *type, Array *array, bool duplicate) : HIR(node, type), - array_(array) + array_(array), + duplicate_(duplicate) { } @@ -176,9 +177,13 @@ Handle array() const { return array_; } + bool duplicate() const { + return duplicate_; + } private: ScopedRoot array_; + bool duplicate_; }; class HConvert : public HIR diff -r 43287eef2fff -r 072f1114ea5d src/compiler/SemanticAnalysis.cpp --- a/src/compiler/SemanticAnalysis.cpp Mon Dec 24 02:56:02 2012 -0800 +++ b/src/compiler/SemanticAnalysis.cpp Mon Dec 24 16:09:13 2012 -0800 @@ -436,7 +436,7 @@ if ((hir = eval(node->initialization())) == NULL) return; - if ((hir = coerce(hir, type, Coerce_Assign)) == NULL) + if ((hir = coerce(hir, type, Coerce_Decl)) == NULL) return; discharge(hir); @@ -455,8 +455,23 @@ if (atype->isFixedLength()) { __ newarray(OP_NEWFIXED, map, InferTenure(node->sym())); - } else if (node->dims()) { - assert(false); + } else if (node->dims()->at(0)) { + // This may not be true if we allow typedefing, so :TODO: + // figure out proper semantics. + assert(node->dims()->length() == atype->levels()); + + Local i32(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32)); + for (size_t i = 0; i < node->dims()->length(); i++) { + Expression *expr = node->dims()->at(i); + if (expr) { + HIR *hir = eval(expr); + if (!hir || ((hir = coerce(hir, i32, Coerce_Arg)) == NULL)) + return; + discharge(hir); + } else { + __ int_(0); + } + } __ newarray(OP_NEWSIZED, map, InferTenure(node->sym())); } else { __ newarray(OP_NEWEMPTY, map, InferTenure(node->sym())); @@ -833,9 +848,7 @@ HString *hir = from->toString(); Local actual(zone_, ArrayType::cast(argActual)); - // If assigning or returning, and the desired type is fixed length, - // make sure there is enough room. - if ((kind == Coerce_Return || kind == Coerce_Assign) && actual->isFixedLength()) { + if (actual->isFixedLength()) { if (hir->string()->length() + 1 > actual->fixedLength()) { cc_.reportError(pos, Message_ArrayAssignmentTooBig); return NULL; @@ -858,7 +871,25 @@ if (!array) return NULL; - return new (pool_) HArray(hir->node(), actual, array); + // Since we're creating a canonical copy of the char array, we have to + // be careful that it doesn't get mutated. There are two cases where + // we know it can't be mutated, and therefore don't need to specify + // that it be cloned after pushing it onto the stack. + // + // (1) The array type is const. + // (2) The array type is fixed-length, and the coercion is for + // assignment, meaning it will be immediately copied. + // + // We treat declaration separately from assignment, since for + // declaration we can just immediately use the cloned version. + bool shouldDuplicate = true; + if (actual->isConst() || + (actual->isFixedLength() && kind == Coerce_Assign)) + { + shouldDuplicate = false; + } + + return new (pool_) HArray(hir->node(), actual, array, shouldDuplicate); } if (!argGiven->isArray()) { @@ -877,23 +908,21 @@ unsigned level = 1; while (true) { if (actual->isFixedLength()) { - if (kind == Coerce_Return || kind == Coerce_Assign) { - if (!given->isFixedLength()) { - cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level); + if (!given->isFixedLength()) { + cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level); + return NULL; + } + + if (actual->isCharArray()) { + // String assignment can have a truncated |given|. + if (given->fixedLength() > actual->fixedLength()) { + cc_.reportError(pos, Message_ArrayAssignmentTooBig); return NULL; } - - if (actual->isCharArray()) { - // String assignment can have a truncated |given|. - if (given->fixedLength() > actual->fixedLength()) { - cc_.reportError(pos, Message_ArrayAssignmentTooBig); - return NULL; - } - } else { - if (given->fixedLength() != actual->fixedLength()) { - cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level); - return NULL; - } + } else { + if (given->fixedLength() != actual->fixedLength()) { + cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level); + return NULL; } } } else if (given->isFixedLength()) { diff -r 43287eef2fff -r 072f1114ea5d src/compiler/SemanticAnalysis.h --- a/src/compiler/SemanticAnalysis.h Mon Dec 24 02:56:02 2012 -0800 +++ b/src/compiler/SemanticAnalysis.h Mon Dec 24 16:09:13 2012 -0800 @@ -85,6 +85,7 @@ enum CoercionKind { Coerce_Arg, Coerce_Return, + Coerce_Decl, Coerce_Assign }; diff -r 43287eef2fff -r 072f1114ea5d tests/basic/string-lit-2.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/string-lit-2.out Mon Dec 24 16:09:13 2012 -0800 @@ -0,0 +1,1 @@ +6568101121 diff -r 43287eef2fff -r 072f1114ea5d tests/basic/string-lit-2.sp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/string-lit-2.sp Mon Dec 24 16:09:13 2012 -0800 @@ -0,0 +1,26 @@ +native PrintNum(num); + +f(x) +{ + new char:str1[]; + new char:str2[4]; + + str1 = "hello"; + str2 = "bye"; + + // Make sure modifying the string doesn't modify the + // canonical literals. + if (x) { + str1[1] = 65; + str2[1] = 68; + } + + PrintNum(str1[1]); + PrintNum(str2[1]); +} + +public main() +{ + f(1); + f(0); +}