# HG changeset patch # User David Anderson # Date 1347758754 25200 # Node ID 10936f3a2ba37d509531cfe6557287d0706ea110 # Parent 387d76b1e981302f4dcaaa125139eb6b4a8ef1d8 Added support for declaring empty-length arrays. diff -r 387d76b1e981 -r 10936f3a2ba3 src/Array.cpp --- a/src/Array.cpp Sat Sep 15 17:39:45 2012 -0700 +++ b/src/Array.cpp Sat Sep 15 18:25:54 2012 -0700 @@ -72,6 +72,14 @@ } Array * +Array::New(Zone *zone, Handle map, Heap::Tenure tenure) +{ + assert(map->type()->isFixedLength()); + + return Array::New(zone, map, map->type()->fixedLength(), tenure); +} + +Array * Array::New(Zone *zone, Handle map, uint32 elements, Heap::Tenure tenure) { size_t elementBytes = SizeFor(map->type(), elements); diff -r 387d76b1e981 -r 10936f3a2ba3 src/Array.h --- a/src/Array.h Sat Sep 15 17:39:45 2012 -0700 +++ b/src/Array.h Sat Sep 15 18:25:54 2012 -0700 @@ -34,6 +34,7 @@ void *elements_; public: + static Array *New(Zone *zone, Handle map, Heap::Tenure = Heap::Tenure_Default); static Array *New(Zone *zone, Handle map, uint32 elements, Heap::Tenure = Heap::Tenure_Default); static Array *NewString(Zone *zone, Handle map, Address buffer, size_t length, Heap::Tenure = Heap::Tenure_Default); diff -r 387d76b1e981 -r 10936f3a2ba3 src/BytecodeCompiler.cpp --- a/src/BytecodeCompiler.cpp Sat Sep 15 17:39:45 2012 -0700 +++ b/src/BytecodeCompiler.cpp Sat Sep 15 18:25:54 2012 -0700 @@ -783,10 +783,17 @@ if (type->isArray()) { Local map(zone_, ArrayMap::Attach(zone_, type)); __ note_position(node->pos()); + + Opcode op; + if (type->isFixedLength()) + op = OP_NEWFIXED; + else + op = OP_NEWEMPTY; + if (var->scope()->kind() == Scope::GLOBAL) - __ newarray(map, Heap::Tenure_Old); + __ newarray(op, map, Heap::Tenure_Old); else - __ newarray(map, Heap::Tenure_Default); + __ newarray(op, map, Heap::Tenure_Default); if (node->initialization()) { node->initialization()->accept(this); @@ -929,9 +936,9 @@ // Natives cannot escape array references, so we can allocate // them on the LIFO stack. if (funType->isNative()) - __ newarray(map, Heap::Tenure_Stack); + __ newarray(OP_NEWFIXED, map, Heap::Tenure_Stack); else - __ newarray(map, Heap::Tenure_Default); + __ newarray(OP_NEWFIXED, map, Heap::Tenure_Default); __ dup(); __ object(array); __ copyarray(); diff -r 387d76b1e981 -r 10936f3a2ba3 src/BytecodeEmitter.h --- a/src/BytecodeEmitter.h Sat Sep 15 17:39:45 2012 -0700 +++ b/src/BytecodeEmitter.h Sat Sep 15 18:25:54 2012 -0700 @@ -436,10 +436,14 @@ void cvt_i2f() { singleByteOp(OP_CVT_I2F); } - void newarray(Handle map, Heap::Tenure tenure) { + void newarray(Opcode op, Handle map, Heap::Tenure tenure) { + assert(op == OP_NEWFIXED || + op == OP_NEWEMPTY || + op == OP_NEWSIZED); + recordOops(); - ensure(OP_NEWARRAY_LENGTH); - writeOp(OP_NEWARRAY); + ensure(OpcodeInfo[op].length); + writeOp(op); writeUint8(tenure); writeObject(map); markOop(1); diff -r 387d76b1e981 -r 10936f3a2ba3 src/Interpreter.cpp --- a/src/Interpreter.cpp Sat Sep 15 17:39:45 2012 -0700 +++ b/src/Interpreter.cpp Sat Sep 15 18:25:54 2012 -0700 @@ -807,11 +807,23 @@ break; } -case OP_NEWARRAY: +case OP_NEWFIXED: { Heap::Tenure tenure = (Heap::Tenure)top.pc[1]; Local map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1)))); - Array *array = Array::New(zone, map, map->type()->declaredLength(), tenure); + Array *array = Array::New(zone, map, tenure); + if (!array) + goto error; + top.sp->obj = array; + top.sp++; + break; +} + +case OP_NEWEMPTY: +{ + Heap::Tenure tenure = (Heap::Tenure)top.pc[1]; + Local map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1)))); + Array *array = Array::New(zone, map, 0, tenure); if (!array) goto error; top.sp->obj = array; diff -r 387d76b1e981 -r 10936f3a2ba3 src/Opcodes.cpp --- a/src/Opcodes.cpp Sat Sep 15 17:39:45 2012 -0700 +++ b/src/Opcodes.cpp Sat Sep 15 18:25:54 2012 -0700 @@ -78,8 +78,14 @@ // safepoint, which is a bug. #ifndef NDEBUG Opcode op = Opcode(*(start() + pcOffset)); - assert(op == OP_CALL || op == OP_NEWARRAY || op == OP_VARREF_LIFO || - op == OP_ARGREF_LIFO || op == OP_SLOTREF_LIFO || op == OP_ARRAYREF_LIFO || + assert(op == OP_CALL || + op == OP_NEWFIXED || + op == OP_NEWEMPTY || + op == OP_NEWSIZED || + op == OP_VARREF_LIFO || + op == OP_ARGREF_LIFO || + op == OP_SLOTREF_LIFO || + op == OP_ARRAYREF_LIFO || op == OP_COPYARRAY); #endif @@ -240,7 +246,9 @@ fprintf(fp, "%u (%+d)", unsigned((pc + READ_INT32(pc)) - code->start()), READ_INT32(pc)); break; - case OP_NEWARRAY: + case OP_NEWFIXED: + case OP_NEWEMPTY: + case OP_NEWSIZED: { Heap::Tenure tenure = (Heap::Tenure)pc[1]; //ArrayMap *map = ArrayMap::cast(code->map(READ_UINT32(pc + 1))); diff -r 387d76b1e981 -r 10936f3a2ba3 src/Opcodes.tbl --- a/src/Opcodes.tbl Sat Sep 15 17:39:45 2012 -0700 +++ b/src/Opcodes.tbl Sat Sep 15 18:25:54 2012 -0700 @@ -103,87 +103,94 @@ OPDEF(OP_GETARG, 38, "getarg", 5, 0, 1) OPDEF(OP_SETARG, 39, "setarg", 5, 1, 1) -// Allocate an array. The HeapTenure is stored as a byte following pc. The -// ArrayMap to use is specified as an index into the script's Map table. +// Allocates either: +// A fixed array, +// A 0-length dynamic array, or +// A dynamic array whose size is specified on the stack. +// +// The HeapTenure is stored as a byte following the pc. The ArrayMap to use +// is specified as an index into the script's object table. // // Format: // [u8 op] [u8 tenure] [u32 index] -OPDEF(OP_NEWARRAY, 40, "newarray", 6, 0, 1) +OPDEF(OP_NEWFIXED, 40, "newfixed", 6, 0, 1) +OPDEF(OP_NEWEMPTY, 41, "newempty", 6, 0, 1) +OPDEF(OP_NEWSIZED, 42, "newsized", 6, 1, 1) // Performs an array-to-array assignment. // Left = pop() // Right = pop() // copy(Left, Right) // push(Left) -OPDEF(OP_COPYARRAY, 41, "arraycopy", 1, 2, 1) +OPDEF(OP_COPYARRAY, 43, "arraycopy", 1, 2, 1) // Reads or writes an integer element to an unsafe array. // index = pop() // ref = pop() // ref[index] // -OPDEF(OP_GETELEM, 42, "getelem", 1, 2, 1) -OPDEF(OP_SETELEM, 43, "setelem", 1, 3, 1) +OPDEF(OP_GETELEM, 44, "getelem", 1, 2, 1) +OPDEF(OP_SETELEM, 45, "setelem", 1, 3, 1) // Pushes a 32-bit IEEE-754 floating point immediate onto the stack. -OPDEF(OP_FLOAT, 44, "float", 5, 0, 1) +OPDEF(OP_FLOAT, 46, "float", 5, 0, 1) // Converts an integer to a 32-bit IEEE-754 floating point immediate. -OPDEF(OP_CVT_I2F, 45, "cvt.i2f", 1, 1, 1) +OPDEF(OP_CVT_I2F, 47, "cvt.i2f", 1, 1, 1) // Stack transitions for these binary operators: // rhs = pop() // lhs = pop() // push(lhs OP rhs) -OPDEF(OP_ADD_F, 46, "add.f", 1, 2, 1) -OPDEF(OP_SUB_F, 47, "sub.f", 1, 2, 1) -OPDEF(OP_MUL_F, 48, "mul.f", 1, 2, 1) -OPDEF(OP_DIV_F, 49, "div.f", 1, 2, 1) +OPDEF(OP_ADD_F, 48, "add.f", 1, 2, 1) +OPDEF(OP_SUB_F, 49, "sub.f", 1, 2, 1) +OPDEF(OP_MUL_F, 50, "mul.f", 1, 2, 1) +OPDEF(OP_DIV_F, 51, "div.f", 1, 2, 1) -OPDEF(OP_LT_F, 50, "lt.f", 1, 2, 1) -OPDEF(OP_LE_F, 51, "le.f", 1, 2, 1) -OPDEF(OP_GE_F, 52, "ge.f", 1, 2, 1) -OPDEF(OP_GT_F, 53, "gt.f", 1, 2, 1) -OPDEF(OP_EQ_F, 54, "eq.f", 1, 2, 1) -OPDEF(OP_NE_F, 55, "ne.f", 1, 2, 1) +OPDEF(OP_LT_F, 52, "lt.f", 1, 2, 1) +OPDEF(OP_LE_F, 53, "le.f", 1, 2, 1) +OPDEF(OP_GE_F, 54, "ge.f", 1, 2, 1) +OPDEF(OP_GT_F, 55, "gt.f", 1, 2, 1) +OPDEF(OP_EQ_F, 56, "eq.f", 1, 2, 1) +OPDEF(OP_NE_F, 57, "ne.f", 1, 2, 1) -OPDEF(OP_NOT_F, 56, "not.f", 1, 1, 1) -OPDEF(OP_NEG_F, 57, "neg.f", 1, 1, 1) +OPDEF(OP_NOT_F, 58, "not.f", 1, 1, 1) +OPDEF(OP_NEG_F, 59, "neg.f", 1, 1, 1) // Bitwise operators. -OPDEF(OP_SHL, 58, "shl", 1, 2, 1) -OPDEF(OP_SHR, 59, "shr", 1, 2, 1) -OPDEF(OP_USHR, 60, "ushr", 1, 2, 1) -OPDEF(OP_BITAND, 61, "bitand", 1, 2, 1) -OPDEF(OP_BITOR, 62, "bitor", 1, 2, 1) -OPDEF(OP_BITXOR, 63, "bitxor", 1, 2, 1) -OPDEF(OP_BITNOT, 64, "bitnot", 1, 1, 1) +OPDEF(OP_SHL, 60, "shl", 1, 2, 1) +OPDEF(OP_SHR, 61, "shr", 1, 2, 1) +OPDEF(OP_USHR, 62, "ushr", 1, 2, 1) +OPDEF(OP_BITAND, 63, "bitand", 1, 2, 1) +OPDEF(OP_BITOR, 64, "bitor", 1, 2, 1) +OPDEF(OP_BITXOR, 65, "bitxor", 1, 2, 1) +OPDEF(OP_BITNOT, 66, "bitnot", 1, 1, 1) // Saves or restores the position of the LIFO heap to/from a local slot. -OPDEF(OP_SAVELIFO, 65, "savelifo", 5, 0, 0) -OPDEF(OP_UNWINDLIFO, 66, "unwindlifo", 5, 0, 0) +OPDEF(OP_SAVELIFO, 67, "savelifo", 5, 0, 0) +OPDEF(OP_UNWINDLIFO, 68, "unwindlifo", 5, 0, 0) // Composes a variable reference to a stack slot or argument. -OPDEF(OP_VARREF_LIFO, 67, "varref.lifo", 5, 0, 1) -OPDEF(OP_ARGREF_LIFO, 68, "argref.lifo", 5, 0, 1) -OPDEF(OP_SLOTREF_LIFO, 69, "slotref.lifo", 1, 1, 1) -OPDEF(OP_ARRAYREF_LIFO, 70, "arrayref.lifo",1, 2, 1) -OPDEF(OP_GETREF_I, 71, "getref.i", 1, 1, 1) -OPDEF(OP_SETREF_I, 72, "setref.i", 1, 2, 1) -OPDEF(OP_GETREF_F, 73, "getref.f", 1, 1, 1) -OPDEF(OP_SETREF_F, 74, "setref.f", 1, 2, 1) +OPDEF(OP_VARREF_LIFO, 69, "varref.lifo", 5, 0, 1) +OPDEF(OP_ARGREF_LIFO, 70, "argref.lifo", 5, 0, 1) +OPDEF(OP_SLOTREF_LIFO, 71, "slotref.lifo", 1, 1, 1) +OPDEF(OP_ARRAYREF_LIFO, 72, "arrayref.lifo",1, 2, 1) +OPDEF(OP_GETREF_I, 73, "getref.i", 1, 1, 1) +OPDEF(OP_SETREF_I, 74, "setref.i", 1, 2, 1) +OPDEF(OP_GETREF_F, 75, "getref.f", 1, 1, 1) +OPDEF(OP_SETREF_F, 76, "setref.f", 1, 2, 1) // Pushes an object reference onto the stack. -OPDEF(OP_OBJECT, 75, "object", 5, 0, 1) +OPDEF(OP_OBJECT, 77, "object", 5, 0, 1) // Duplicates the top item on the stack. -OPDEF(OP_DUP, 76, "dup", 1, 1, 2) +OPDEF(OP_DUP, 78, "dup", 1, 1, 2) // Duplicates the top two items on the stack. -OPDEF(OP_DUP2, 77, "dup2", 1, 2, 4) +OPDEF(OP_DUP2, 79, "dup2", 1, 2, 4) // Swaps the two items at the top of the stack. -OPDEF(OP_SWAP, 78, "swap", 1, 2, 2) +OPDEF(OP_SWAP, 80, "swap", 1, 2, 2) // Roll operation is the same as Forth. It steals a value on the stack, // shifting all stack values down, and then places the stolen value back at @@ -193,14 +200,14 @@ // sp[-3] = sp[-2] // sp[-2] = sp[-1] // sp[-1] = p -OPDEF(OP_ROLL3, 79, "roll3", 1, 3, 3) +OPDEF(OP_ROLL3, 81, "roll3", 1, 3, 3) // Pick operation is the same as Forth. It pushes a copy of a slot at a // specific depth. // // push(sp[-n]) -OPDEF(OP_PICK2, 80, "pick2", 1, 2, 3) -OPDEF(OP_PICK3, 81, "pick3", 1, 3, 4) +OPDEF(OP_PICK2, 82, "pick2", 1, 2, 3) +OPDEF(OP_PICK3, 83, "pick3", 1, 3, 4) // Calls a native function. During the course of calling a native, arguments // on the stack are re-pushed to match the cell-based native calling @@ -211,57 +218,57 @@ // // [u8 Opcode] [u32 Index] [u32 ArgCount] // -OPDEF(OP_CALLNATIVE, 82, "callnative", 9, -1, 1) +OPDEF(OP_CALLNATIVE, 84, "callnative", 9, -1, 1) // Returns from a function that does return a value. -OPDEF(OP_RETURNVOID, 83, "returnvoid", 1, 0, 0) +OPDEF(OP_RETURNVOID, 85, "returnvoid", 1, 0, 0) // Loads the module of the running function. -OPDEF(OP_MODULE, 84, "module", 1, 0, 1) +OPDEF(OP_MODULE, 86, "module", 1, 0, 1) // Loads a function from a module object. The operand is the slot number // in the module. -OPDEF(OP_GETMODULE_FN, 85, "getmodule.fn", 5, 1, 1) +OPDEF(OP_GETMODULE_FN, 87, "getmodule.fn", 5, 1, 1) // Opcodes for accessing an environment slot in the global scope. -OPDEF(OP_SETGLOBAL_I, 86, "setglobal.i", 5, 1, 1) -OPDEF(OP_SETGLOBAL_F, 87, "setglobal.f", 5, 1, 1) -OPDEF(OP_SETGLOBAL_O, 88, "setglobal.o", 5, 1, 1) -OPDEF(OP_GETGLOBAL_I, 89, "getglobal.i", 5, 0, 1) -OPDEF(OP_GETGLOBAL_F, 90, "getglobal.f", 5, 0, 1) -OPDEF(OP_GETGLOBAL_O, 91, "getglobal.o", 5, 0, 1) +OPDEF(OP_SETGLOBAL_I, 88, "setglobal.i", 5, 1, 1) +OPDEF(OP_SETGLOBAL_F, 89, "setglobal.f", 5, 1, 1) +OPDEF(OP_SETGLOBAL_O, 90, "setglobal.o", 5, 1, 1) +OPDEF(OP_GETGLOBAL_I, 91, "getglobal.i", 5, 0, 1) +OPDEF(OP_GETGLOBAL_F, 92, "getglobal.f", 5, 0, 1) +OPDEF(OP_GETGLOBAL_O, 93, "getglobal.o", 5, 0, 1) // Reinterprets a 32-bit integer as a float, or vice-versa. -OPDEF(OP_BITS_I2F, 92, "bits.i2f", 1, 1, 1) -OPDEF(OP_BITS_F2I, 93, "bits.f2i", 1, 1, 1) +OPDEF(OP_BITS_I2F, 94, "bits.i2f", 1, 1, 1) +OPDEF(OP_BITS_F2I, 95, "bits.f2i", 1, 1, 1) // Pushes a boolean value. -OPDEF(OP_TRUE, 94, "true", 1, 0, 1) -OPDEF(OP_FALSE, 95, "false", 1, 0, 1) +OPDEF(OP_TRUE, 96, "true", 1, 0, 1) +OPDEF(OP_FALSE, 97, "false", 1, 0, 1) // Allocate a struct. The HeapTenure is stored as a byte following pc. The // StructMap to use is specified as an index into the script's Map table. // // Format: // [u8 op] [u8 tenure] [u32 index] -OPDEF(OP_NEWSTRUCT, 96, "newstruct", 6, 0, 1) +OPDEF(OP_NEWSTRUCT, 98, "newstruct", 6, 0, 1) // Performs a struct-to-struct assignment. // Left = pop() // Right = pop() // copy(Left, Right) // push(Left) -OPDEF(OP_COPYSTRUCT, 97, "structcopy", 1, 2, 1) +OPDEF(OP_COPYSTRUCT, 99, "structcopy", 1, 2, 1) // Sets or gets a property in a struct. The index of the field is specified as // a 32-bit integer. Note that these opcodes follow a new style of deriving // their types at runtime. -OPDEF(OP_GETFIELD, 98, "getfield", 5, 1, 1) -OPDEF(OP_SETFIELD, 99, "setfield", 5, 2, 1) +OPDEF(OP_GETFIELD, 100, "getfield", 5, 1, 1) +OPDEF(OP_SETFIELD, 101, "setfield", 5, 2, 1) -OPDEF(OP_FIELDREF_LIFO, 100, "fieldref.lifo", 5, 1, 1) +OPDEF(OP_FIELDREF_LIFO, 102, "fieldref.lifo", 5, 1, 1) // Table-based jump. // [u8 op] [i32 low] [i32 high] [u32 jump] [u32 jumps...] -OPDEF(OP_TABLESWITCH, 101, "tableswitch", 9, 1, 0) +OPDEF(OP_TABLESWITCH, 103, "tableswitch", 9, 1, 0) diff -r 387d76b1e981 -r 10936f3a2ba3 src/SemanticAnalysis.cpp --- a/src/SemanticAnalysis.cpp Sat Sep 15 17:39:45 2012 -0700 +++ b/src/SemanticAnalysis.cpp Sat Sep 15 18:25:54 2012 -0700 @@ -782,19 +782,13 @@ return; } } else { - // Infer the size from the initializer. - if (!init) { - cc_.reportError(node->pos(), Message_ArraySizeNotSpecified); - return; - } - if (!init->isFixedLength()) { - cc_.reportError(node->pos(), Message_ArraySizeCannotBeDetermined); - return; - } - size = init->fixedLength(); + if (init && init->isFixedLength()) + size = init->fixedLength(); + else + size = Type::DYNAMIC_ARRAY_SIZE; } - type = zone_->types()->unsafeArray(type, size, false); + type = zone_->types()->newArray(type, size, false); if (!type) return; @@ -941,7 +935,7 @@ size = box.toInt(); } - type = zone_->types()->unsafeArray(type, size, parameter->isConst()); + type = zone_->types()->newArray(type, size, parameter->isConst()); if (!type) return false; } diff -r 387d76b1e981 -r 10936f3a2ba3 src/TypeManager.cpp --- a/src/TypeManager.cpp Sat Sep 15 17:39:45 2012 -0700 +++ b/src/TypeManager.cpp Sat Sep 15 18:25:54 2012 -0700 @@ -65,7 +65,7 @@ } Type * -TypeManager::unsafeArray(Handle contained, int elements, bool isConst) +TypeManager::newArray(Handle contained, int elements, bool isConst) { // :TODO: cache this. return Type::NewArray(zone_, contained, elements, isConst); diff -r 387d76b1e981 -r 10936f3a2ba3 src/TypeManager.h --- a/src/TypeManager.h Sat Sep 15 17:39:45 2012 -0700 +++ b/src/TypeManager.h Sat Sep 15 18:25:54 2012 -0700 @@ -53,7 +53,7 @@ return uncheckedType_; } Type *getReference(Handle type, bool isConst); - Type *unsafeArray(Handle contained, int elements, bool isConst); + Type *newArray(Handle contained, int elements, bool isConst); Type *newEnum(Handle name); Type *newFunction(Handle returnType, Handle args, Handle deafults); diff -r 387d76b1e981 -r 10936f3a2ba3 src/Zone.cpp --- a/src/Zone.cpp Sat Sep 15 17:39:45 2012 -0700 +++ b/src/Zone.cpp Sat Sep 15 18:25:54 2012 -0700 @@ -114,7 +114,7 @@ if (!type) return false; - type = types_->unsafeArray(type, Type::DYNAMIC_ARRAY_SIZE, false); + type = types_->newArray(type, Type::DYNAMIC_ARRAY_SIZE, false); if (!type) return false; @@ -126,7 +126,7 @@ if (!type) return false; - type = types_->unsafeArray(type, Type::DYNAMIC_ARRAY_SIZE, false); + type = types_->newArray(type, Type::DYNAMIC_ARRAY_SIZE, false); if (!type) return false;