src/BytecodeCompiler.cpp
changeset 187 9308d52205a0
parent 185 10936f3a2ba3
child 188 bab29bcec7fe
     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  {