1.1 --- a/src/BytecodeCompiler.cpp Sat Sep 15 19:33:24 2012 -0700
1.2 +++ b/src/BytecodeCompiler.cpp Sun Sep 16 19:02:23 2012 -0700
1.3 @@ -739,20 +739,25 @@
1.4 __ float_((float)node->value());
1.5 }
1.6
1.7 +static inline Array *
1.8 +StringLiteralToArray(Zone *zone, StringLiteral *node)
1.9 +{
1.10 + Local<Type> type(zone, node->type());
1.11 + Local<ArrayMap> map(zone, ArrayMap::Attach(zone, type));
1.12 + if (!map)
1.13 + return NULL;
1.14 +
1.15 + return Array::NewString(zone,
1.16 + map,
1.17 + node->string()->raw(),
1.18 + node->string()->length(),
1.19 + Heap::Tenure_Old);
1.20 +}
1.21 +
1.22 void
1.23 BytecodeCompiler::visit(StringLiteral *node)
1.24 {
1.25 - Local<Type> type(zone_, node->type());
1.26 - Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
1.27 - if (!map)
1.28 - return;
1.29 -
1.30 - Local<Array> array(zone_,
1.31 - Array::NewString(zone_,
1.32 - map,
1.33 - node->string()->raw(),
1.34 - node->string()->length(),
1.35 - Heap::Tenure_Old));
1.36 + Local<Array> array(zone_, StringLiteralToArray(zone_, node));
1.37 if (!array)
1.38 return;
1.39
1.40 @@ -774,6 +779,106 @@
1.41 __ setglobal(var);
1.42 }
1.43
1.44 +static bool
1.45 +FillArrayLiteral_String(Zone *zone, Handle<Array> array, ArrayLiteral *literal, unsigned *maxsize)
1.46 +{
1.47 + Local<Array> string(zone);
1.48 + for (size_t i = 0; i < literal->expressions()->length(); i++) {
1.49 + Expression *expr = literal->expressions()->at(i);
1.50 + StringLiteral *lit = expr->toStringLiteral();
1.51 + if ((string = StringLiteralToArray(zone, lit)) == NULL)
1.52 + return false;
1.53 +
1.54 + array->writeObject(zone, i, string);
1.55 +
1.56 + if (string->length() > *maxsize)
1.57 + *maxsize = string->length();
1.58 +
1.59 + assert(!array->type()->contained()->isFixedLength() ||
1.60 + array->type()->contained()->fixedLength() >= string->length());
1.61 + }
1.62 +
1.63 + return true;
1.64 +}
1.65 +
1.66 +static bool
1.67 +FillArrayLiteral_Primitive(Zone *zone, Handle<Array> array, ArrayLiteral *literal)
1.68 +{
1.69 + assert(array->type()->fixedLength() == literal->expressions()->length());
1.70 +
1.71 + for (size_t i = 0; i < literal->expressions()->length(); i++) {
1.72 + Expression *expr = literal->expressions()->at(i);
1.73 + if (IntegerLiteral *lit = expr->asIntegerLiteral()) {
1.74 + array->writeInt32(i, lit->value());
1.75 + continue;
1.76 + }
1.77 + if (BooleanLiteral *lit = expr->asBooleanLiteral()) {
1.78 + if (lit->token() == TOK_TRUE)
1.79 + array->writeInt32(i, 1);
1.80 + else
1.81 + array->writeInt32(i, 0);
1.82 + continue;
1.83 + }
1.84 + if (FloatLiteral *lit = expr->asFloatLiteral()) {
1.85 + array->writeFloat(i, lit->value());
1.86 + continue;
1.87 + }
1.88 +
1.89 + // Unrecognized literal type.
1.90 + assert(false);
1.91 + }
1.92 +
1.93 + return true;
1.94 +}
1.95 +
1.96 +static bool
1.97 +TraverseArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<Array> array, Handle<Type> type,
1.98 + unsigned *maxsize)
1.99 +{
1.100 + assert(type->fixedLength() == literal->expressions()->length());
1.101 +
1.102 + Local<Type> contained(zone, type->contained());
1.103 + if (contained->isCharArray())
1.104 + return FillArrayLiteral_String(zone, array, literal, maxsize);
1.105 +
1.106 + if (!contained->isArray())
1.107 + return FillArrayLiteral_Primitive(zone, array, literal);
1.108 +
1.109 + Local<Array> subarray(zone);
1.110 + for (size_t i = 0; i < literal->expressions()->length(); i++) {
1.111 + Expression *expr = literal->expressions()->at(i);
1.112 + subarray = Array::cast(array->readObject(i));
1.113 + if (!TraverseArrayLiteral(zone, expr->toArrayLiteral(), subarray, contained, maxsize))
1.114 + return false;
1.115 + }
1.116 +
1.117 + return true;
1.118 +}
1.119 +
1.120 +static Array *
1.121 +BuildArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<ArrayMap> map, unsigned *maxsize)
1.122 +{
1.123 + Local<Array> root(zone, Array::NewFixed(zone, map, Heap::Tenure_Old));
1.124 + if (!root)
1.125 + return NULL;
1.126 +
1.127 + // This should have allocated everything in the array, so all we need to
1.128 + // do is traverse down to the lowest levels and copy things.
1.129 + Local<Type> type(zone, map->type());
1.130 + if (!TraverseArrayLiteral(zone, literal, root, type, maxsize))
1.131 + return NULL;
1.132 +
1.133 + return root;
1.134 +}
1.135 +
1.136 +static inline bool
1.137 +ArrayContainsCharBuffers(Type *type)
1.138 +{
1.139 + if (type->contained()->isArray())
1.140 + return ArrayContainsCharBuffers(type->contained());
1.141 + return type->isCharArray();
1.142 +}
1.143 +
1.144 void
1.145 BytecodeCompiler::visit(VariableDeclaration *node)
1.146 {
1.147 @@ -784,21 +889,91 @@
1.148 Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
1.149 __ note_position(node->pos());
1.150
1.151 - Opcode op;
1.152 - if (type->isFixedLength())
1.153 - op = OP_NEWFIXED;
1.154 - else
1.155 - op = OP_NEWEMPTY;
1.156 + Local<Type> right(zone_);
1.157 + if (node->initialization())
1.158 + right = node->initialization()->type();
1.159 +
1.160 + // There are a few methods for allocating, here:
1.161 + // (1) If the array is fixed,
1.162 + // (a) Initializer not present,
1.163 + // NEWFIXED
1.164 + // (b) Left is const non-string:
1.165 + // <nothing>
1.166 + // (b) Otherwise:
1.167 + // NEWFIXED
1.168 + // COPYARRAY
1.169 + // (2) If the array is not fixed,
1.170 + // (a) Initializer is not present,
1.171 + // NEWEMPTY
1.172 + // (b) Initializer is not a string literal,
1.173 + // or left is const:
1.174 + // <nothing>
1.175 + // (c) Initializer is a string literal,
1.176 + // NEWSIZED
1.177 + // COPYARRAY
1.178 + //
1.179 +
1.180 + Heap::Tenure tenure = var->scope()->kind() == Scope::GLOBAL
1.181 + ? Heap::Tenure_Old
1.182 + : Heap::Tenure_Default;
1.183 +
1.184 + if (Expression *init = node->initialization()) {
1.185 + if (init->isArrayLiteral()) {
1.186 + unsigned maxsize = 0;
1.187 + Local<Array> array(zone_, BuildArrayLiteral(zone_, init->toArrayLiteral(), map, &maxsize));
1.188 + if (!array)
1.189 + return;
1.190 +
1.191 + assert(type->isFixedLength());
1.192
1.193 - if (var->scope()->kind() == Scope::GLOBAL)
1.194 - __ newarray(op, map, Heap::Tenure_Old);
1.195 - else
1.196 - __ newarray(op, map, Heap::Tenure_Default);
1.197 -
1.198 - if (node->initialization()) {
1.199 - node->initialization()->accept(this);
1.200 - __ note_position(node->pos());
1.201 - __ copyarray();
1.202 + if (type->isConst()) {
1.203 + __ object(array);
1.204 + } else if (ArrayContainsCharBuffers(type)) {
1.205 + // This array contains mutable char buffers, so
1.206 + // unfortunately this gets a little more complicated. We
1.207 + // compute the maximum size needed for the innermost
1.208 + // string, which is similar to SP1. This means we can use
1.209 + // CopyArray rather than individually emit opcodes to clone
1.210 + // every string.
1.211 + Local<Type> child(zone_, type);
1.212 + for (size_t i = 0; i < type->levels() - 1; i++) {
1.213 + __ int_(child->fixedLength());
1.214 + child = child->contained();
1.215 + }
1.216 + __ int_(maxsize);
1.217 + __ newarray(OP_NEWSIZED, map, tenure);
1.218 + __ object(array);
1.219 + __ copyarray();
1.220 + } else {
1.221 + __ newarray(OP_NEWFIXED, map, tenure);
1.222 + __ object(array);
1.223 + __ copyarray();
1.224 + }
1.225 + } else if (type->isFixedLength()) {
1.226 + // Note in the case of:
1.227 + // const String:buffer[50] = "hello";
1.228 + //
1.229 + // We want to preserve sizeof(buffer) == 50.
1.230 + if (type->isConst() && !type->isCharArray()) {
1.231 + init->accept(this);
1.232 + } else {
1.233 + __ newarray(OP_NEWFIXED, map, tenure);
1.234 + init->accept(this);
1.235 + __ copyarray();
1.236 + }
1.237 + } else if (!type->isConst() && init->isStringLiteral()) {
1.238 + // This is a degenerate case of ArrayLiteral.
1.239 + __ int_(right->fixedLength());
1.240 + __ newarray(OP_NEWSIZED, map, tenure);
1.241 + init->accept(this);
1.242 + __ copyarray();
1.243 + } else if (type->isConst()) {
1.244 + init->accept(this);
1.245 + }
1.246 + } else if (type->isFixedLength()) {
1.247 + __ newarray(OP_NEWFIXED, map, tenure);
1.248 + } else {
1.249 + __ newarray(OP_NEWEMPTY, map, tenure);
1.250 }
1.251 } else if (type->isStruct()) {
1.252 Local<Map> map(zone_, type->newMap());
1.253 @@ -1157,6 +1332,14 @@
1.254 {
1.255 }
1.256
1.257 +void
1.258 +BytecodeCompiler::visit(ArrayLiteral *node)
1.259 +{
1.260 + // We shouldn't reach these; they're handled manually when initializing
1.261 + // declared arrays.
1.262 + assert(false);
1.263 +}
1.264 +
1.265 Code *
1.266 BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
1.267 {