src/OldByCo.cpp
changeset 195 c1ba166f3fc4
child 263 ba85a47ee414
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/OldByCo.cpp	Sat Nov 17 18:41:01 2012 -0800
     1.3 @@ -0,0 +1,1585 @@
     1.4 +/* vim: set ts=4 sw=4 tw=99 et:
     1.5 + *
     1.6 + * Copyright (C) 2012 David Anderson
     1.7 + *
     1.8 + * This file is part of JITCraft.
     1.9 + *
    1.10 + * JITCraft is free software: you can redistribute it and/or modify it under
    1.11 + * the terms of the GNU General Public License as published by the Free
    1.12 + * Software Foundation, either version 3 of the License, or (at your option)
    1.13 + * any later version.
    1.14 + * 
    1.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    1.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    1.18 + *
    1.19 + * You should have received a copy of the GNU General Public License along with
    1.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
    1.21 + */
    1.22 +#include <string.h>
    1.23 +#include "../Modules.h"
    1.24 +#include "../Types.h"
    1.25 +#include "../Array.h"
    1.26 +#include "../Strings.h"
    1.27 +#include "../Zone.h"
    1.28 +#include "../Environments.h"
    1.29 +#include "../Box.h"
    1.30 +#include "../Heap-inl.h"
    1.31 +#include "BytecodeCompiler.h"
    1.32 +#include "Scopes.h"
    1.33 +
    1.34 +using namespace ke;
    1.35 +
    1.36 +typedef BytecodeEmitter::Label Label;
    1.37 +
    1.38 +#define __ emitter_.
    1.39 +
    1.40 +BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
    1.41 +  : zone_(zone),
    1.42 +    tree_(tree),
    1.43 +    emitter_(zone->pool()),
    1.44 +    locals_(NULL),
    1.45 +    scope_(NULL),
    1.46 +    moduleData_(module),
    1.47 +    loop_(NULL)
    1.48 +{
    1.49 +}
    1.50 +
    1.51 +static inline TokenKind
    1.52 +ToCompare(Expression *expr)
    1.53 +{
    1.54 +    if (expr->isBinaryExpression()) {
    1.55 +        BinaryExpression *b = expr->toBinaryExpression();
    1.56 +        if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
    1.57 +            return b->token();
    1.58 +    } else if (expr->isUnaryExpression()) {
    1.59 +        UnaryExpression *u = expr->toUnaryExpression();
    1.60 +        if (u->token() == TOK_NOT)
    1.61 +            return TOK_NOT;
    1.62 +    }
    1.63 +    return TOK_EOF;
    1.64 +}
    1.65 +
    1.66 +static inline Opcode
    1.67 +CompareTokenToJump(TokenKind kind)
    1.68 +{
    1.69 +    switch (kind) {
    1.70 +      case TOK_EQUALS:
    1.71 +        return OP_JEQ;
    1.72 +      case TOK_NOTEQUALS:
    1.73 +        return OP_JNE;
    1.74 +      case TOK_GT:
    1.75 +        return OP_JG;
    1.76 +      case TOK_GE:
    1.77 +        return OP_JGE;
    1.78 +      case TOK_LT:
    1.79 +        return OP_JL;
    1.80 +      default:
    1.81 +        assert(kind == TOK_LE);
    1.82 +        return OP_JLE;
    1.83 +    }
    1.84 +}
    1.85 +
    1.86 +static inline Opcode
    1.87 +TokenToOpcode(TokenKind kind)
    1.88 +{
    1.89 +    switch (kind) {
    1.90 +      case TOK_PLUS:
    1.91 +        return OP_ADD;
    1.92 +      case TOK_MINUS:
    1.93 +        return OP_SUB;
    1.94 +      case TOK_STAR:
    1.95 +        return OP_MUL;
    1.96 +      case TOK_SLASH:
    1.97 +        return OP_DIV;
    1.98 +      case TOK_PERCENT:
    1.99 +        return OP_MOD;
   1.100 +      case TOK_SHR:
   1.101 +        return OP_SHR;
   1.102 +      case TOK_USHR:
   1.103 +        return OP_USHR;
   1.104 +      case TOK_SHL:
   1.105 +        return OP_SHL;
   1.106 +      case TOK_BITAND:
   1.107 +        return OP_BITAND;
   1.108 +      case TOK_BITOR:
   1.109 +        return OP_BITOR;
   1.110 +      case TOK_GT:
   1.111 +          return OP_GT;
   1.112 +      case TOK_GE:
   1.113 +          return OP_GE;
   1.114 +      case TOK_LT:
   1.115 +          return OP_LT;
   1.116 +      case TOK_LE:
   1.117 +          return OP_LE;
   1.118 +      case TOK_EQUALS:
   1.119 +          return OP_EQ;
   1.120 +      case TOK_NOTEQUALS:
   1.121 +          return OP_NE;
   1.122 +      default:
   1.123 +        assert(kind == TOK_BITXOR);
   1.124 +        return OP_BITXOR;
   1.125 +    }
   1.126 +}
   1.127 +
   1.128 +void
   1.129 +BytecodeCompiler::recordLifoSlot(Scope *scope)
   1.130 +{
   1.131 +    if (!scope)
   1.132 +        return;
   1.133 +
   1.134 +    if (Variable *var = scope->lifoSlot()) {
   1.135 +        locals_->set(zone_, var->slot(), var->type());
   1.136 +        __ savelifo(var->slot());
   1.137 +    }
   1.138 +}
   1.139 +
   1.140 +void
   1.141 +BytecodeCompiler::unwindTo(Scope *scope)
   1.142 +{
   1.143 +    // Note: we only need to unwind to the outermost scope's LIFO slot.
   1.144 +    Variable *var = NULL;
   1.145 +    for (Scope *current = scope_; current != scope; current = current->enclosing()) {
   1.146 +        if (Variable *slot = current->lifoSlot())
   1.147 +            var = slot;
   1.148 +    }
   1.149 +
   1.150 +    if (var)
   1.151 +        __ unwindlifo(var->slot());
   1.152 +}
   1.153 +
   1.154 +void
   1.155 +BytecodeCompiler::visit(NameProxy *name)
   1.156 +{
   1.157 +    switch (name->binding()->kind()) {
   1.158 +      case BoundName::VARIABLE:
   1.159 +      {
   1.160 +        Variable *var = name->binding()->toVariable();
   1.161 +
   1.162 +        if (var->location() == Variable::STACK) {
   1.163 +            __ getlocal(var);
   1.164 +            assert(!name->type()->isReference());
   1.165 +        } else if (var->location() == Variable::ENVIRONMENT) {
   1.166 +            getEnvSlot(var);
   1.167 +        } else {
   1.168 +            assert(var->location() == Variable::PARAMETER);
   1.169 +            __ getarg(var);
   1.170 +
   1.171 +            // If this argument is actually a reference, dereference it now.
   1.172 +            if (var->type()->isReference())
   1.173 +                __ getref(var->type()->contained());
   1.174 +        }
   1.175 +        break;
   1.176 +      }
   1.177 +
   1.178 +      case BoundName::FUNCTION:
   1.179 +      {
   1.180 +        NamedFunction *fun = name->binding()->toNamedFunction();
   1.181 +        __ module();
   1.182 +        __ getmodule_fn(fun->slot());
   1.183 +        break;
   1.184 +      }
   1.185 +
   1.186 +      default:
   1.187 +      {
   1.188 +        NamedConstant *constant = name->binding()->toNamedConstant();
   1.189 +        __ int_(constant->value().toInt());
   1.190 +        break;
   1.191 +      }
   1.192 +    }
   1.193 +}
   1.194 +
   1.195 +void
   1.196 +BytecodeCompiler::visit(ExpressionStatement *node)
   1.197 +{
   1.198 +    // Expressions leave their value on the top of the stack, so we make sure
   1.199 +    // to balance the stack if they're used as a statement.
   1.200 +    node->expression()->accept(this);
   1.201 +    if (!node->expression()->type()->isVoid())
   1.202 +        __ pop();
   1.203 +}
   1.204 +
   1.205 +static inline bool
   1.206 +IsCompositeValueType(Type *type)
   1.207 +{
   1.208 +    return type->isStruct() ||
   1.209 +           (type->isArray() && type->isFixedLength());
   1.210 +}
   1.211 +
   1.212 +static inline Array *
   1.213 +StringLiteralToArray(Zone *zone, StringLiteral *node)
   1.214 +{
   1.215 +    Local<Type> type(zone, node->type());
   1.216 +    Local<ArrayMap> map(zone, ArrayMap::Attach(zone, type));
   1.217 +    if (!map)
   1.218 +        return NULL;
   1.219 +
   1.220 +    return Array::NewString(zone,
   1.221 +                            map,
   1.222 +                            node->string()->raw(),
   1.223 +                            node->string()->length(),
   1.224 +                            Heap::Tenure_Old);
   1.225 +}
   1.226 +
   1.227 +void
   1.228 +BytecodeCompiler::visit(Assignment *node)
   1.229 +{
   1.230 +    Local<Type> left(zone_, node->type());
   1.231 +    Local<Type> right(zone_, node->expression()->type());
   1.232 +
   1.233 +    // The first step is three sub-steps:
   1.234 +    //
   1.235 +    //   (1) Bind the left-hand side.
   1.236 +    //   -- If a cumulative operation (+=, etc):
   1.237 +    //   (2) Save a copy of the binding on the stack.
   1.238 +    //   (3) Dereference the binding to get a value.
   1.239 +    //
   1.240 +    if (node->lvalue()->isNameProxy()) {
   1.241 +        NameProxy *proxy = node->lvalue()->toNameProxy();
   1.242 +        Variable *var = proxy->binding()->toVariable();
   1.243 +
   1.244 +        // We need to fetch the variable under the following circumstances:
   1.245 +        //  (1) The variable is a reference, since we'll store into the ref.
   1.246 +        //  (2) The variable is a fixed array, since we need to copy into it.
   1.247 +        //  (3) The variable is a struct, since we need to copy into it.
   1.248 +        if (var->type()->isReference() || IsCompositeValueType(var->type()))
   1.249 +            __ get(var);
   1.250 +
   1.251 +        // Get the value if needed.
   1.252 +        if (node->token() != TOK_ASSIGN) {
   1.253 +            // += etc is not allowed on arrays.
   1.254 +            assert(!var->type()->isArray());
   1.255 +
   1.256 +            if (var->location() == Variable::ENVIRONMENT)
   1.257 +                getEnvSlot(var);
   1.258 +
   1.259 +            if (var->type()->isReference()) {
   1.260 +                __ dup();
   1.261 +                __ getref(var->type()->contained());
   1.262 +            } else if (var->location() != Variable::ENVIRONMENT) {
   1.263 +                __ get(var);
   1.264 +            }
   1.265 +        }
   1.266 +    } else if (node->lvalue()->isFieldExpression()) {
   1.267 +        FieldExpression *expr = node->lvalue()->toFieldExpression();
   1.268 +        __ note_position(expr->pos());
   1.269 +
   1.270 +        expr->left()->accept(this);
   1.271 +
   1.272 +        if (node->token() != TOK_ASSIGN)
   1.273 +            __ dup();
   1.274 +
   1.275 +        if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
   1.276 +            __ getfield(expr->fieldIndex(), left);
   1.277 +    } else {
   1.278 +        IndexExpression *index = node->lvalue()->toIndexExpression();
   1.279 +        __ note_position(index->pos());
   1.280 +
   1.281 +        index->left()->accept(this);
   1.282 +        index->right()->accept(this);
   1.283 +
   1.284 +        if (node->token() != TOK_ASSIGN)
   1.285 +            __ dup2();
   1.286 +
   1.287 +        if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
   1.288 +            __ getelem(left);
   1.289 +    }
   1.290 +
   1.291 +    if (node->token() == TOK_ASSIGN) {
   1.292 +        // Special case: if the left-hand side is a string literal, we must
   1.293 +        // spawn a new copy (:TODO: something about const?)
   1.294 +        if (node->expression()->isStringLiteral() && !left->isFixedLength()) {
   1.295 +            Local<Array> string(zone_,
   1.296 +                    StringLiteralToArray(zone_, node->expression()->toStringLiteral()));
   1.297 +            if (!string)
   1.298 +                return;
   1.299 +
   1.300 +            Local<ArrayMap> arrayMap(zone_, ArrayMap::cast(string->map()));
   1.301 +            __ note_position(node->expression()->pos());
   1.302 +            __ int_(string->length());
   1.303 +            __ newarray(OP_NEWSIZED, arrayMap, Heap::Tenure_Default);
   1.304 +            __ object(string);
   1.305 +            __ copyarray();
   1.306 +        } else {
   1.307 +            node->expression()->accept(this);
   1.308 +        }
   1.309 +    } else {
   1.310 +        visitForALU(left, node->expression());
   1.311 +
   1.312 +        TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
   1.313 +        __ note_position(node->pos());
   1.314 +        __ binary(TokenToOpcode(alu));
   1.315 +    }
   1.316 +
   1.317 +    // Emit the store.
   1.318 +    if (left->isArray() && left->isFixedLength()) {
   1.319 +        // (x = y) returns the left-hand side; if |x| is a fixed-length array,
   1.320 +        // then |y| is as well, and we perform a deep copy.
   1.321 +        assert(right->isFixedLength());
   1.322 +        __ note_position(node->pos());
   1.323 +        __ copyarray();
   1.324 +    } else if (left->isStruct()) {
   1.325 +        // Structs have value semantics, so emit a full copy. We don't break
   1.326 +        // this down into u-ops, to avoid unnecessary bytecode explosion.
   1.327 +        assert(right->isStruct());
   1.328 +        __ note_position(node->pos());
   1.329 +        __ copystruct();
   1.330 +    } else if (node->lvalue()->isNameProxy()) {
   1.331 +        NameProxy *proxy = node->lvalue()->toNameProxy();
   1.332 +        Variable *var = proxy->binding()->toVariable();
   1.333 +
   1.334 +        if (var->type()->isReference())
   1.335 +            __ setref(var->type()->contained());
   1.336 +        else if (var->location() == Variable::ENVIRONMENT)
   1.337 +            setEnvSlot(var);
   1.338 +        else
   1.339 +            __ set(var);
   1.340 +    } else if (node->lvalue()->isFieldExpression()) {
   1.341 +        FieldExpression *expr = node->lvalue()->toFieldExpression();
   1.342 +        __ setfield(expr->fieldIndex(), left);
   1.343 +    } else {
   1.344 +        __ setelem(left);
   1.345 +    }
   1.346 +}
   1.347 +
   1.348 +void
   1.349 +BytecodeCompiler::visit(IncDecExpression *node)
   1.350 +{
   1.351 +    // In the postfix case, the logic looks like:
   1.352 +    //      (1) Bind       -> REF
   1.353 +    //      (2) Dup        -> REF REF
   1.354 +    //      (3) Fetch      -> REF VAL
   1.355 +    //      (4) Swap       -> VAL REF
   1.356 +    //      (5) Pick       -> VAL REF VAL
   1.357 +    //      (6) Add        -> VAL REF VAL+1
   1.358 +    //      (7) Store      -> VAL VAL+1
   1.359 +    //      (8) Drop       -> VAL
   1.360 +    //
   1.361 +    // In the prefix case, the logic looks like:
   1.362 +    //      (1) Bind       -> REF
   1.363 +    //      (2) Dup        -> REF REF
   1.364 +    //      (3) Fetch      -> REF VAL
   1.365 +    //      --
   1.366 +    //      --
   1.367 +    //      (6) Add        -> REF VAL+1
   1.368 +    //      (7) Store      -> VAL+1
   1.369 +    //      --
   1.370 +    //
   1.371 +    // This is squirrely enough such that we don't bother sharing too much
   1.372 +    // with the above.
   1.373 +    // 
   1.374 +    // Note: We simulate a "Pick" operation with a dup2+pop.
   1.375 +
   1.376 +    // This is steps (1) to (5).
   1.377 +    Expression *expr = node->expression();
   1.378 +    if (expr->isNameProxy()) {
   1.379 +        NameProxy *proxy = expr->toNameProxy();
   1.380 +        Variable *var = proxy->binding()->toVariable();
   1.381 +
   1.382 +        // Bind.
   1.383 +        if (var->location() == Variable::ENVIRONMENT)
   1.384 +            getEnvSlot(var);
   1.385 +        else if (var->type()->isReference() || var->type()->isArray())
   1.386 +            __ get(var);
   1.387 +
   1.388 +        // Dup and fetch.
   1.389 +        if (var->type()->isReference()) {
   1.390 +            __ dup();
   1.391 +            __ getref(node->type());
   1.392 +            if (node->postfix()) {
   1.393 +                __ swap();
   1.394 +                __ pick2();
   1.395 +            }
   1.396 +        } else {
   1.397 +            assert(!var->type()->isArray());
   1.398 +            if (var->location() != Variable::ENVIRONMENT)
   1.399 +                __ get(var);
   1.400 +            if (node->postfix())
   1.401 +                __ dup();
   1.402 +        }
   1.403 +    } else if (expr->isFieldExpression()) {
   1.404 +        FieldExpression *field = expr->toFieldExpression();
   1.405 +
   1.406 +        field->left()->accept(this);
   1.407 +        __ dup();
   1.408 +        __ getfield(field->fieldIndex(), field->type());
   1.409 +
   1.410 +        if (node->postfix()) {
   1.411 +            // The stack looks like this now:
   1.412 +            // OBJECT VALUE
   1.413 +            __ swap();          // VALUE OBJECT
   1.414 +            __ pick2();         // VALUE OBJECT VALUE
   1.415 +        }
   1.416 +    } else {
   1.417 +        IndexExpression *index = expr->toIndexExpression();
   1.418 +        __ note_position(index->pos());
   1.419 +
   1.420 +        index->left()->accept(this);
   1.421 +        index->right()->accept(this);
   1.422 +
   1.423 +        assert(!node->type()->isArray());
   1.424 +        __ dup2();
   1.425 +        __ getelem(node->type());
   1.426 +
   1.427 +        if (node->postfix()) {
   1.428 +            // The stack looks like this now:
   1.429 +            // ARRAY INDEX VALUE
   1.430 +            //
   1.431 +            // So we must use a PICK operation to rotate the stack into position.
   1.432 +            __ roll3();         // INDEX VALUE ARRAY
   1.433 +            __ roll3();         // VALUE ARRAY INDEX
   1.434 +            __ pick3();         // VALUE ARRAY INDEX VALUE
   1.435 +        }
   1.436 +    }
   1.437 +
   1.438 +    // Perform step (6).
   1.439 +    if (node->type()->isFloat()) {
   1.440 +        __ float_(1.0);
   1.441 +    } else {
   1.442 +        assert(node->type()->isInt32());
   1.443 +        __ int_(1);
   1.444 +    }
   1.445 +
   1.446 +    __ note_position(node->pos());
   1.447 +    if (node->token() == TOK_INCREMENT)
   1.448 +        __ binary(OP_ADD);
   1.449 +    else
   1.450 +        __ binary(OP_SUB);
   1.451 +
   1.452 +    // Perform step (7).
   1.453 +    if (expr->isNameProxy()) {
   1.454 +        NameProxy *proxy = expr->toNameProxy();
   1.455 +        Variable *var = proxy->binding()->toVariable();
   1.456 +
   1.457 +        if (var->type()->isReference())
   1.458 +            __ setref(node->type());
   1.459 +        else if (var->location() == Variable::ENVIRONMENT)
   1.460 +            setEnvSlot(var);
   1.461 +        else
   1.462 +            __ set(var);
   1.463 +    } else if (expr->isFieldExpression()) {
   1.464 +        FieldExpression *field = expr->toFieldExpression();
   1.465 +        __ setfield(field->fieldIndex(), field->type());
   1.466 +    } else {
   1.467 +        assert(expr->isIndexExpression());
   1.468 +        __ setelem(node->type());
   1.469 +    }
   1.470 +
   1.471 +    // Perform step (8).
   1.472 +    if (node->postfix())
   1.473 +        __ pop();
   1.474 +}
   1.475 +
   1.476 +void
   1.477 +BytecodeCompiler::visitForALU(Type *needed, Expression *node)
   1.478 +{
   1.479 +    node->accept(this);
   1.480 +    if (needed->isFloat() && !node->type()->isFloat())
   1.481 +        __ cvt_i2f();
   1.482 +    else
   1.483 +        assert(needed->primitive() == node->type()->primitive());
   1.484 +}
   1.485 +
   1.486 +static inline Type *
   1.487 +GetCoercionType(TokenKind tok, Type *left, Type *right)
   1.488 +{
   1.489 +    if (left->isFloat())
   1.490 +        return left;
   1.491 +    return right;
   1.492 +}
   1.493 +
   1.494 +void
   1.495 +BytecodeCompiler::visit(UnaryExpression *node)
   1.496 +{
   1.497 +    Local<Type> out(zone_, ((Expression *)node)->type());
   1.498 +
   1.499 +    switch (node->token()) {
   1.500 +      case TOK_MINUS:
   1.501 +      {
   1.502 +        Local<Type> type(zone_, node->expression()->type());
   1.503 +        node->expression()->accept(this);
   1.504 +        
   1.505 +        if (out->isFloat())
   1.506 +            __ neg_f();
   1.507 +        else
   1.508 +            __ neg();
   1.509 +        break;
   1.510 +      }
   1.511 +
   1.512 +      case TOK_NOT:
   1.513 +      {
   1.514 +        Local<Type> type(zone_, node->expression()->type());
   1.515 +        node->expression()->accept(this);
   1.516 +        
   1.517 +        if (out->isFloat())
   1.518 +            __ not_f();
   1.519 +        else
   1.520 +            __ not_();
   1.521 +        break;
   1.522 +      }
   1.523 +
   1.524 +      case TOK_LABEL:
   1.525 +      {
   1.526 +        Local<Type> from(zone_, node->expression()->type());
   1.527 +
   1.528 +        node->expression()->accept(this);
   1.529 +        if (!from->isFloat() && out->isFloat())
   1.530 +            __ bits_f2i();
   1.531 +        else if (from->isFloat() && !out->isFloat())
   1.532 +            __ bits_i2f();
   1.533 +        break;
   1.534 +      }
   1.535 +
   1.536 +      case TOK_SIZEOF:
   1.537 +      {
   1.538 +        Local<Type> type(zone_, node->expression()->type());
   1.539 +        if (type->isFixedLength()) {
   1.540 +            __ int_(type->fixedLength());
   1.541 +        } else {
   1.542 +            node->expression()->accept(this);
   1.543 +            __ sizeof_();
   1.544 +        }
   1.545 +        break;
   1.546 +      }
   1.547 +
   1.548 +      default:
   1.549 +        assert(node->token() == TOK_TILDE);
   1.550 +        node->expression()->accept(this);
   1.551 +        __ bitnot();
   1.552 +        break;
   1.553 +    }
   1.554 +}
   1.555 +
   1.556 +void
   1.557 +BytecodeCompiler::visit(BinaryExpression *node)
   1.558 +{
   1.559 +    if (node->token() == TOK_AND || node->token() == TOK_OR) {
   1.560 +        Label success, failure, done;
   1.561 +        visitForTest(node, &success, &failure, &success);
   1.562 +        __ bind(&success);
   1.563 +        __ int_(1);
   1.564 +        __ drop(1);         // Otherwise, the stack depth will be +1 too much.
   1.565 +        __ jump(&done);
   1.566 +        __ bind(&failure);
   1.567 +        __ int_(0);
   1.568 +        __ bind(&done);
   1.569 +        return;
   1.570 +    }
   1.571 +
   1.572 +    Local<Type> leftType(zone_, node->left()->type());
   1.573 +    Local<Type> rightType(zone_, node->right()->type());
   1.574 +    Local<Type> coerce(zone_, GetCoercionType(node->token(), leftType, rightType));
   1.575 +
   1.576 +    visitForALU(coerce, node->left());
   1.577 +    visitForALU(coerce, node->right());
   1.578 +
   1.579 +    Opcode op = TokenToOpcode(node->token());
   1.580 +    if (node->type()->isFloat())
   1.581 +        op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
   1.582 +
   1.583 +    __ note_position(node->pos());
   1.584 +    __ binary(op);
   1.585 +}
   1.586 +
   1.587 +void
   1.588 +BytecodeCompiler::visit(IndexExpression *node)
   1.589 +{
   1.590 +    node->left()->accept(this);
   1.591 +    node->right()->accept(this);
   1.592 +    __ note_position(node->pos());
   1.593 +    __ getelem(node->type());
   1.594 +}
   1.595 +
   1.596 +void
   1.597 +BytecodeCompiler::visit(FieldExpression *node)
   1.598 +{
   1.599 +    node->left()->accept(this);
   1.600 +    __ getfield(node->fieldIndex(), node->type());
   1.601 +}
   1.602 +
   1.603 +void
   1.604 +BytecodeCompiler::visit(ReturnStatement *node)
   1.605 +{
   1.606 +    if (node->expression()) {
   1.607 +        node->expression()->accept(this);
   1.608 +        __ return_();
   1.609 +    } else {
   1.610 +        __ returnvoid();
   1.611 +    }
   1.612 +}
   1.613 +
   1.614 +void
   1.615 +BytecodeCompiler::visitForTest(Expression *expression,
   1.616 +                               Label *trueBranch,
   1.617 +                               Label *falseBranch,
   1.618 +                               Label *fallthrough)
   1.619 +{
   1.620 +    TokenKind token = ToCompare(expression);
   1.621 +    if (token == TOK_EOF || token == TOK_NOT) {
   1.622 +        if (token == TOK_EOF)
   1.623 +            expression->accept(this);
   1.624 +        else
   1.625 +            expression->toUnaryExpression()->expression()->accept(this);
   1.626 +        
   1.627 +        bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
   1.628 +
   1.629 +        Opcode op = jumpOnTrue ? OP_JT : OP_JF;
   1.630 +        if (expression->type()->isFloat())
   1.631 +            op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
   1.632 +
   1.633 +        if (fallthrough == falseBranch)
   1.634 +            __ j(op, trueBranch);
   1.635 +        else
   1.636 +            __ j(op, falseBranch); 
   1.637 +        return;
   1.638 +    }
   1.639 +
   1.640 +    BinaryExpression *binary = expression->toBinaryExpression();
   1.641 +
   1.642 +    if (token == TOK_AND || token == TOK_OR) {
   1.643 +        Label next;
   1.644 +        if (token == TOK_AND)
   1.645 +            visitForTest(binary->left(), &next, falseBranch, &next);
   1.646 +        else
   1.647 +            visitForTest(binary->left(), trueBranch, &next, &next);
   1.648 +        __ bind(&next);
   1.649 +        visitForTest(binary->right(), trueBranch, falseBranch, fallthrough);
   1.650 +        return;
   1.651 +    }
   1.652 +
   1.653 +    Opcode op = CompareTokenToJump(token);
   1.654 +    if (fallthrough == trueBranch)
   1.655 +        op = Invert(op);
   1.656 +
   1.657 +    Local<Type> leftType(zone_, binary->left()->type());
   1.658 +    Local<Type> rightType(zone_, binary->right()->type());
   1.659 +    Local<Type> coerce(zone_, GetCoercionType(binary->token(), leftType, rightType));
   1.660 +
   1.661 +    visitForALU(coerce, binary->left());
   1.662 +    visitForALU(coerce, binary->right());
   1.663 +    if (coerce->isFloat())
   1.664 +        op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
   1.665 +
   1.666 +    if (fallthrough == trueBranch)
   1.667 +        __ j(op, falseBranch);
   1.668 +    else
   1.669 +        __ j(op, trueBranch);
   1.670 +}
   1.671 +
   1.672 +void
   1.673 +BytecodeCompiler::visit(ForStatement *node)
   1.674 +{
   1.675 +    AutoEnterScope forScope(this, node->scope());
   1.676 +
   1.677 +    recordLifoSlot(node->scope());
   1.678 +
   1.679 +    Label join, update;
   1.680 +    LoopScope loop(scope_, &join, &update, &loop_);
   1.681 +
   1.682 +    if (node->initialization())
   1.683 +        node->initialization()->accept(this);
   1.684 +
   1.685 +    Label header, test;
   1.686 +    if (node->condition())
   1.687 +        __ jump(&test);
   1.688 +
   1.689 +    __ bind(&header);
   1.690 +    node->body()->accept(this);
   1.691 +
   1.692 +    __ bind(&update);
   1.693 +    if (node->update())
   1.694 +        node->update()->accept(this);
   1.695 +
   1.696 +    if (node->condition()) {
   1.697 +        __ bind(&test);
   1.698 +        visitForTest(node->condition(), &header, &join, &join);
   1.699 +    } else {
   1.700 +        __ jump(&header);
   1.701 +    }
   1.702 +
   1.703 +    __ bind(&join);
   1.704 +
   1.705 +    if (node->scope())
   1.706 +        unwindTo(node->scope()->enclosing());
   1.707 +    assert(__ stackDepth() == 0);
   1.708 +}
   1.709 +
   1.710 +void
   1.711 +BytecodeCompiler::visit(WhileStatement *node)
   1.712 +{
   1.713 +    Label header, join;
   1.714 +
   1.715 +    __ bind(&header);
   1.716 +
   1.717 +    LoopScope loop(scope_, &join, &header, &loop_);
   1.718 +
   1.719 +    if (node->token() == TOK_WHILE) {
   1.720 +        Label body;
   1.721 +
   1.722 +        visitForTest(node->condition(), &body, &join, &body);
   1.723 +        __ bind(&body);
   1.724 +        node->body()->accept(this);
   1.725 +        __ jump(&header);
   1.726 +    } else {
   1.727 +        node->body()->accept(this);
   1.728 +        visitForTest(node->condition(), &header, &join, &join);
   1.729 +    }
   1.730 +
   1.731 +    __ bind(&join);
   1.732 +}
   1.733 +
   1.734 +void
   1.735 +BytecodeCompiler::visit(BreakStatement *node)
   1.736 +{
   1.737 +    unwindTo(loop_->scope());
   1.738 +    __ jump(loop_->break_());
   1.739 +}
   1.740 +
   1.741 +void
   1.742 +BytecodeCompiler::visit(ContinueStatement *node)
   1.743 +{
   1.744 +    unwindTo(loop_->scope());
   1.745 +    __ jump(loop_->continue_());
   1.746 +}
   1.747 +
   1.748 +void
   1.749 +BytecodeCompiler::visit(BlockStatement *node)
   1.750 +{
   1.751 +    AutoEnterScope blockScope(this, node->scope());
   1.752 +
   1.753 +    recordLifoSlot(node->scope());
   1.754 +
   1.755 +    for (size_t i = 0; i < node->statements()->length(); i++) {
   1.756 +        Statement *statement = node->statements()->at(i);
   1.757 +        statement->accept(this);
   1.758 +        assert(__ stackDepth() == 0);
   1.759 +    }
   1.760 +
   1.761 +    // We don't bother emitting an "unwind" instruction for function scopes,
   1.762 +    // since this is taken care of by the calling convention.
   1.763 +    if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
   1.764 +        unwindTo(node->scope()->enclosing());
   1.765 +}
   1.766 +
   1.767 +void
   1.768 +BytecodeCompiler::visit(IntegerLiteral *node)
   1.769 +{
   1.770 +    __ int_(node->value());
   1.771 +}
   1.772 +
   1.773 +void
   1.774 +BytecodeCompiler::visit(BooleanLiteral *node)
   1.775 +{
   1.776 +    if (node->token() == TOK_TRUE)
   1.777 +        __ true_();
   1.778 +    else
   1.779 +        __ false_();
   1.780 +}
   1.781 +
   1.782 +void
   1.783 +BytecodeCompiler::visit(FloatLiteral *node)
   1.784 +{
   1.785 +    __ float_((float)node->value());
   1.786 +}
   1.787 +
   1.788 +void
   1.789 +BytecodeCompiler::visit(StringLiteral *node)
   1.790 +{
   1.791 +    Local<Array> array(zone_, StringLiteralToArray(zone_, node));
   1.792 +    if (!array)
   1.793 +        return;
   1.794 +
   1.795 +    __ note_position(node->pos());
   1.796 +    __ object(array);
   1.797 +}
   1.798 +
   1.799 +void
   1.800 +BytecodeCompiler::getEnvSlot(Variable *var)
   1.801 +{
   1.802 +    assert(var->scope()->kind() == Scope::GLOBAL);
   1.803 +    __ getglobal(var);
   1.804 +}
   1.805 +
   1.806 +void
   1.807 +BytecodeCompiler::setEnvSlot(Variable *var)
   1.808 +{
   1.809 +    assert(var->scope()->kind() == Scope::GLOBAL);
   1.810 +    __ setglobal(var);
   1.811 +}
   1.812 +
   1.813 +static bool
   1.814 +FillArrayLiteral_String(Zone *zone, Handle<Array> array, ArrayLiteral *literal, unsigned *maxsize)
   1.815 +{
   1.816 +    Local<Array> string(zone);
   1.817 +    for (size_t i = 0; i < literal->expressions()->length(); i++) {
   1.818 +        Expression *expr = literal->expressions()->at(i);
   1.819 +        StringLiteral *lit = expr->toStringLiteral();
   1.820 +        if ((string = StringLiteralToArray(zone, lit)) == NULL)
   1.821 +            return false;
   1.822 +
   1.823 +        array->writeObject(zone, i, string);
   1.824 +
   1.825 +        if (string->length() > *maxsize)
   1.826 +            *maxsize = string->length();
   1.827 +
   1.828 +        assert(!array->type()->contained()->isFixedLength() ||
   1.829 +                array->type()->contained()->fixedLength() >= string->length());
   1.830 +    }
   1.831 +
   1.832 +    return true;
   1.833 +}
   1.834 +
   1.835 +static bool
   1.836 +FillArrayLiteral_Primitive(Zone *zone, Handle<Array> array, ArrayLiteral *literal)
   1.837 +{
   1.838 +    assert(array->type()->fixedLength() == literal->expressions()->length());
   1.839 +
   1.840 +    for (size_t i = 0; i < literal->expressions()->length(); i++) {
   1.841 +        Expression *expr = literal->expressions()->at(i);
   1.842 +        if (IntegerLiteral *lit = expr->asIntegerLiteral()) {
   1.843 +            array->writeInt32(i, lit->value());
   1.844 +            continue;
   1.845 +        }
   1.846 +        if (BooleanLiteral *lit = expr->asBooleanLiteral()) {
   1.847 +            if (lit->token() == TOK_TRUE)
   1.848 +                array->writeInt32(i, 1);
   1.849 +            else
   1.850 +                array->writeInt32(i, 0);
   1.851 +            continue;
   1.852 +        }
   1.853 +        if (FloatLiteral *lit = expr->asFloatLiteral()) {
   1.854 +            array->writeFloat(i, (float)lit->value());
   1.855 +            continue;
   1.856 +        }
   1.857 +
   1.858 +        // Unrecognized literal type.
   1.859 +        assert(false);
   1.860 +    }
   1.861 +
   1.862 +    return true;
   1.863 +}
   1.864 +
   1.865 +static bool
   1.866 +TraverseArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<Array> array, Handle<Type> type,
   1.867 +                     unsigned *maxsize)
   1.868 +{
   1.869 +    assert(type->fixedLength() == literal->expressions()->length());
   1.870 +
   1.871 +    Local<Type> contained(zone, type->contained());
   1.872 +    if (contained->isCharArray())
   1.873 +        return FillArrayLiteral_String(zone, array, literal, maxsize);
   1.874 +
   1.875 +    if (!contained->isArray())
   1.876 +        return FillArrayLiteral_Primitive(zone, array, literal);
   1.877 +
   1.878 +    Local<Array> subarray(zone);
   1.879 +    for (size_t i = 0; i < literal->expressions()->length(); i++) {
   1.880 +        Expression *expr = literal->expressions()->at(i);
   1.881 +        subarray = Array::cast(array->readObject(i));
   1.882 +        if (!TraverseArrayLiteral(zone, expr->toArrayLiteral(), subarray, contained, maxsize))
   1.883 +            return false;
   1.884 +    }
   1.885 +
   1.886 +    return true;
   1.887 +}
   1.888 +
   1.889 +static Array *
   1.890 +BuildArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<ArrayMap> map, unsigned *maxsize)
   1.891 +{
   1.892 +    Local<Array> root(zone, Array::NewFixed(zone, map, Heap::Tenure_Old));
   1.893 +    if (!root)
   1.894 +        return NULL;
   1.895 +
   1.896 +    // This should have allocated everything in the array, so all we need to
   1.897 +    // do is traverse down to the lowest levels and copy things.
   1.898 +    Local<Type> type(zone, map->type());
   1.899 +    if (!TraverseArrayLiteral(zone, literal, root, type, maxsize))
   1.900 +        return NULL;
   1.901 +
   1.902 +    return root;
   1.903 +}
   1.904 +
   1.905 +static inline bool
   1.906 +ArrayContainsCharBuffers(Type *type)
   1.907 +{
   1.908 +    if (type->contained()->isArray())
   1.909 +        return ArrayContainsCharBuffers(type->contained());
   1.910 +    return type->isCharArray();
   1.911 +}
   1.912 +
   1.913 +void
   1.914 +BytecodeCompiler::visit(VariableDeclaration *node)
   1.915 +{
   1.916 +    Variable *var = node->variable();
   1.917 +    
   1.918 +    Local<Type> type(zone_, var->type());
   1.919 +    if (type->isArray()) {
   1.920 +        Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
   1.921 +        __ note_position(node->pos());
   1.922 +
   1.923 +        Local<Type> right(zone_);
   1.924 +        if (node->initialization())
   1.925 +            right = node->initialization()->type();
   1.926 +
   1.927 +        // There are a few methods for allocating, here:
   1.928 +        // (1) If the array is fixed,
   1.929 +        //    (a) Initializer not present,
   1.930 +        //              NEWFIXED
   1.931 +        //    (b) Left is const non-string:
   1.932 +        //              <nothing>
   1.933 +        //    (b) Otherwise:
   1.934 +        //              NEWFIXED
   1.935 +        //              COPYARRAY
   1.936 +        // (2) If the array is not fixed,
   1.937 +        //    (a) Initializer is not present,
   1.938 +        //              NEWEMPTY
   1.939 +        //    (b) Initializer is not a string literal,
   1.940 +        //        or left is const:
   1.941 +        //              <nothing>
   1.942 +        //    (c) Initializer is a string literal,
   1.943 +        //              NEWSIZED
   1.944 +        //              COPYARRAY
   1.945 +        //
   1.946 +
   1.947 +        Heap::Tenure tenure = var->scope()->kind() == Scope::GLOBAL
   1.948 +                              ? Heap::Tenure_Old
   1.949 +                              : Heap::Tenure_Default;
   1.950 +
   1.951 +        if (Expression *init = node->initialization()) {
   1.952 +            if (init->isArrayLiteral()) {
   1.953 +                unsigned maxsize = 0;
   1.954 +                Local<Array> array(zone_, BuildArrayLiteral(zone_, init->toArrayLiteral(), map, &maxsize));
   1.955 +                if (!array)
   1.956 +                    return;
   1.957 +
   1.958 +                assert(type->isFixedLength());
   1.959 +
   1.960 +                if (type->isConst()) {
   1.961 +                    __ object(array);
   1.962 +                } else if (ArrayContainsCharBuffers(type)) {
   1.963 +                    // This array contains mutable char buffers, so
   1.964 +                    // unfortunately this gets a little more complicated. We
   1.965 +                    // compute the maximum size needed for the innermost
   1.966 +                    // string, which is similar to SP1. This means we can use
   1.967 +                    // CopyArray rather than individually emit opcodes to clone
   1.968 +                    // every string.
   1.969 +                    Local<Type> child(zone_, type);
   1.970 +                    for (size_t i = 0; i < type->levels() - 1; i++) {
   1.971 +                        __ int_(child->fixedLength());
   1.972 +                        child = child->contained();
   1.973 +                    }
   1.974 +                    __ int_(maxsize);
   1.975 +                    __ newarray(OP_NEWSIZED, map, tenure);
   1.976 +                    __ object(array);
   1.977 +                    __ copyarray();
   1.978 +                } else {
   1.979 +                    __ newarray(OP_NEWFIXED, map, tenure);
   1.980 +                    __ object(array);
   1.981 +                    __ copyarray();
   1.982 +                }
   1.983 +            } else if (type->isFixedLength()) {
   1.984 +                // Note in the case of:
   1.985 +                // const String:buffer[50] = "hello";
   1.986 +                //
   1.987 +                // We want to preserve sizeof(buffer) == 50.
   1.988 +                if (type->isConst() && !type->isCharArray()) {
   1.989 +                    init->accept(this);
   1.990 +                } else {
   1.991 +                    __ newarray(OP_NEWFIXED, map, tenure);
   1.992 +                    init->accept(this);
   1.993 +                    __ copyarray();
   1.994 +                }
   1.995 +            } else if (!type->isConst() && init->isStringLiteral()) {
   1.996 +                // This is a degenerate case of ArrayLiteral.
   1.997 +                __ int_(right->fixedLength());
   1.998 +                __ newarray(OP_NEWSIZED, map, tenure);
   1.999 +                init->accept(this);
  1.1000 +                __ copyarray();
  1.1001 +            } else if (type->isConst()) {
  1.1002 +                init->accept(this);
  1.1003 +            }
  1.1004 +        } else if (type->isFixedLength()) {
  1.1005 +            __ newarray(OP_NEWFIXED, map, tenure);
  1.1006 +        } else {
  1.1007 +#if 0
  1.1008 +            if (node->postDimensions()) {
  1.1009 +                for (size_t i = 0; i < node->postDimensions()->length(); i++) {
  1.1010 +                    Expression *expr = node->postDimensions()->at(i);
  1.1011 +                    if (expr)
  1.1012 +                        expr->accept(this);
  1.1013 +                    else
  1.1014 +                        __ int_(0);
  1.1015 +                }
  1.1016 +                __ newarray(OP_NEWSIZED, map, tenure);
  1.1017 +            } else {
  1.1018 +                __ newarray(OP_NEWEMPTY, map, tenure);
  1.1019 +            }
  1.1020 +#endif
  1.1021 +        }
  1.1022 +    } else if (type->isStruct()) {
  1.1023 +        Local<StructMap> map(zone_, StructMap::cast(type->newMap()));
  1.1024 +
  1.1025 +        // Because structs can contain arrays, any sort of composition
  1.1026 +        // triggers non-LIFO allocation. This is just for correctness.
  1.1027 +        // We could do better by:
  1.1028 +        //  (1) Limiting to structs that just (recursively) contain arrays,
  1.1029 +        //  (2) Swap Stack for Default tenure in Struct::New
  1.1030 +        //  (3) JIT analysis
  1.1031 +        if (var->scope()->kind() == Scope::GLOBAL)
  1.1032 +            __ newstruct(map, Heap::Tenure_Old);
  1.1033 +        else if (var->needsHeapAllocation() || map->composed())
  1.1034 +            __ newstruct(map, Heap::Tenure_Default);
  1.1035 +        else
  1.1036 +            __ newstruct(map, Heap::Tenure_Stack);
  1.1037 +    } else {
  1.1038 +        if (node->initialization()) {
  1.1039 +            node->initialization()->accept(this);
  1.1040 +        } else {
  1.1041 +            if (type->isInt32OrEnum() || type->isBool()) {
  1.1042 +                __ int_(0);
  1.1043 +            } else {
  1.1044 +                assert(type->isFloat());
  1.1045 +                __ float_(0);
  1.1046 +            }
  1.1047 +        }
  1.1048 +    }
  1.1049 +
  1.1050 +    if (var->location() == Variable::STACK) {
  1.1051 +        __ setlocal(var);
  1.1052 +        locals_->set(zone_, var->slot(), var->type());
  1.1053 +    } else {
  1.1054 +        assert(var->location() == Variable::ENVIRONMENT);
  1.1055 +        setEnvSlot(var);
  1.1056 +    }
  1.1057 +
  1.1058 +    __ pop();
  1.1059 +}
  1.1060 +
  1.1061 +void
  1.1062 +BytecodeCompiler::visit(CallExpression *node)
  1.1063 +{
  1.1064 +#if 0
  1.1065 +    Local<Type> funType(zone_, node->callee()->type());
  1.1066 +
  1.1067 +    // Sniff out natives, which have a specific opcode and are guaranteed to
  1.1068 +    // be called via name proxy.
  1.1069 +    NamedFunction *native = NULL;
  1.1070 +    if (funType->isNative())
  1.1071 +        native = node->callee()->toNameProxy()->binding()->toNamedFunction();
  1.1072 +
  1.1073 +    Local<Type> given(zone_);
  1.1074 +    for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
  1.1075 +        Expression *arg = node->arguments()->at(i);
  1.1076 +
  1.1077 +        given = arg->type();
  1.1078 +
  1.1079 +        // We need to compute a reference if the parameter was in the form:
  1.1080 +        //  f(&a)
  1.1081 +        // Note this form does not allow: f({})
  1.1082 +        // 
  1.1083 +        // We also need to compute references for all variadic native
  1.1084 +        // arguments, but arrays and references are already in the
  1.1085 +        // appropriate form.
  1.1086 +        bool mustPushReference = false;
  1.1087 +        if (i >= funType->parameters()->length()) {
  1.1088 +            assert(funType->isNative() && funType->isNativeVariadic());
  1.1089 +            mustPushReference = !given->isArray() && !given->isReference();
  1.1090 +        } else if (funType->parameterAt(i)->isReference()) {
  1.1091 +            mustPushReference = !given->isReference();
  1.1092 +        }
  1.1093 +
  1.1094 +        // If a native is passed to a native, it must only be one level deep.
  1.1095 +        assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
  1.1096 +
  1.1097 +        if (mustPushReference) {
  1.1098 +            if (arg->isNameProxy()) {
  1.1099 +                // :TODO: test with functions and globals
  1.1100 +                // Compute a reference to the name.
  1.1101 +                Variable *var = arg->toNameProxy()->binding()->toVariable();
  1.1102 +                __ note_position(node->pos());
  1.1103 +                __ newref(var);
  1.1104 +            } else if (arg->isFieldExpression()) {
  1.1105 +                FieldExpression *expr = arg->toFieldExpression();
  1.1106 +                expr->left()->accept(this);
  1.1107 +                __ note_position(expr->pos());
  1.1108 +                __ fieldref_lifo(expr->fieldIndex());
  1.1109 +            } else {
  1.1110 +                // We don't know how to, or can't, build a direct reference to
  1.1111 +                // this type. Make an indirect one, by taking the top of the
  1.1112 +                // stack and boxing it up.
  1.1113 +                arg->accept(this);
  1.1114 +                __ note_position(node->pos());
  1.1115 +                __ slotref_lifo();
  1.1116 +            }
  1.1117 +        } else {
  1.1118 +            arg->accept(this);
  1.1119 +        }
  1.1120 +    }
  1.1121 +
  1.1122 +    unsigned argc = node->arguments()->length();
  1.1123 +
  1.1124 +    // If there are missing arguments, then we're not done and have to push
  1.1125 +    // default parameters.
  1.1126 +    Local<Box> box(zone_);
  1.1127 +    Local<Array> array(zone_);
  1.1128 +    Local<ArrayMap> map(zone_);
  1.1129 +    for (size_t i = node->arguments()->length(); i < funType->parameters()->length(); i++) {
  1.1130 +        box = Box::cast(funType->defaults()->at(i));
  1.1131 +
  1.1132 +        if (box->type()->isPod()) {
  1.1133 +            if (box->type()->pod() == PrimitiveType_Int32)
  1.1134 +                __ int_(box->toInt32());
  1.1135 +            else if (box->type()->pod() == PrimitiveType_Float)
  1.1136 +                __ float_(box->toFloat());
  1.1137 +            else
  1.1138 +                assert(false);
  1.1139 +
  1.1140 +            if (funType->parameterAt(i)->isReference()) {
  1.1141 +                __ note_position(node->pos());
  1.1142 +                __ slotref_lifo();
  1.1143 +            }
  1.1144 +        } else {
  1.1145 +            assert(box->type()->isArray());
  1.1146 +
  1.1147 +            array = Array::cast(box->toObject());
  1.1148 +            if (funType->parameterAt(i)->isConst()) {
  1.1149 +                __ object(array);
  1.1150 +            } else {
  1.1151 +                // We need to copy the array since it's mutable. Note that
  1.1152 +                // although COPYARRAY returns its left-hand side, this may
  1.1153 +                // change in the future, we do the same thing and dupe the
  1.1154 +                // newly allocated array.
  1.1155 +                map = ArrayMap::cast(array->map());
  1.1156 +                
  1.1157 +                // Natives cannot escape array references, so we can allocate
  1.1158 +                // them on the LIFO stack.
  1.1159 +                if (funType->isNative())
  1.1160 +                    __ newarray(OP_NEWFIXED, map, Heap::Tenure_Stack);
  1.1161 +                else
  1.1162 +                    __ newarray(OP_NEWFIXED, map, Heap::Tenure_Default);
  1.1163 +                __ dup();
  1.1164 +                __ object(array);
  1.1165 +                __ copyarray();
  1.1166 +                __ pop();
  1.1167 +            }
  1.1168 +        }
  1.1169 +
  1.1170 +        argc++;
  1.1171 +    }
  1.1172 +
  1.1173 +    __ note_position(node->pos());
  1.1174 +    if (native) {
  1.1175 +        __ callnative(native->slot(), argc);
  1.1176 +        __ drop(argc);
  1.1177 +    } else {
  1.1178 +        node->callee()->accept(this);
  1.1179 +        __ call(funType);
  1.1180 +        __ drop(argc + 1);
  1.1181 +    }
  1.1182 +#endif
  1.1183 +}
  1.1184 +
  1.1185 +void
  1.1186 +BytecodeCompiler::visit(TernaryExpression *node)
  1.1187 +{
  1.1188 +    Label success, failure, join;
  1.1189 +
  1.1190 +    visitForTest(node->condition(), &success, &failure, &success);
  1.1191 +    __ bind(&success);
  1.1192 +    node->left()->accept(this);
  1.1193 +    __ drop(1);
  1.1194 +    __ jump(&join);
  1.1195 +    __ bind(&failure);
  1.1196 +    node->right()->accept(this);
  1.1197 +    __ bind(&join);
  1.1198 +}
  1.1199 +
  1.1200 +void
  1.1201 +BytecodeCompiler::visit(IfStatement *node)
  1.1202 +{
  1.1203 +    Label join;
  1.1204 +    if (!node->ifFalse()) {
  1.1205 +        Label success;
  1.1206 +
  1.1207 +        visitForTest(node->condition(), &success, &join, &success);
  1.1208 +        __ bind(&success);
  1.1209 +        node->ifTrue()->accept(this);
  1.1210 +    } else {
  1.1211 +        Label success, next;
  1.1212 +
  1.1213 +        visitForTest(node->condition(), &success, &next, &success);
  1.1214 +        __ bind(&success);
  1.1215 +        node->ifTrue()->accept(this);
  1.1216 +        __ jump(&join);
  1.1217 +        __ bind(&next);
  1.1218 +        node->ifFalse()->accept(this);
  1.1219 +    }
  1.1220 +
  1.1221 +    __ bind(&join);
  1.1222 +}
  1.1223 +
  1.1224 +bool
  1.1225 +BytecodeCompiler::tableswitch(SwitchStatement *node)
  1.1226 +{
  1.1227 +    CaseValueList *values = node->caseValueList();
  1.1228 +
  1.1229 +    if (values->length() < 3)
  1.1230 +        return false;
  1.1231 +
  1.1232 +    // Find the delta between the largest and smallest value.
  1.1233 +    int hi = values->at(values->length() - 1).box.toInt();
  1.1234 +    int lo = values->at(0).box.toInt();
  1.1235 +    assert(hi > lo);
  1.1236 +
  1.1237 +    unsigned tablesize = TableSwitchEntries(lo, hi);
  1.1238 +    if (tablesize > MAX_TABLESWITCH_ENTRIES)
  1.1239 +        return false;
  1.1240 +
  1.1241 +    Label def, join;
  1.1242 +
  1.1243 +    // Create the list of labels that each statement will bind to.
  1.1244 +    Label *labels = new Label[node->cases()->length()];
  1.1245 +
  1.1246 +    // Create the table of labels we'll use for each case.
  1.1247 +    Label **table = new Label *[tablesize];
  1.1248 +
  1.1249 +    // Link all cases, by default, to the default label.
  1.1250 +    for (size_t i = 0; i < tablesize; i++)
  1.1251 +        table[i] = &def;
  1.1252 +
  1.1253 +    // Now patch actual cases to their correct labels.
  1.1254 +    for (size_t i = 0; i < values->length(); i++) {
  1.1255 +        CaseValue &v = values->at(i);
  1.1256 +        assert(v.statement < node->cases()->length());
  1.1257 +
  1.1258 +        unsigned index = unsigned(v.box.toInt() - lo);
  1.1259 +        assert(index < tablesize);
  1.1260 +
  1.1261 +        table[index] = &labels[v.statement];
  1.1262 +    }
  1.1263 +
  1.1264 +    // Emit the tableswitch opcode and the jump table.
  1.1265 +    __ tableswitch(lo, hi, &def, table);
  1.1266 +
  1.1267 +    // We're done with the jump table now.
  1.1268 +    delete [] table;
  1.1269 +
  1.1270 +    // Emit each statement.
  1.1271 +    for (size_t i = 0; i < node->cases()->length(); i++) {
  1.1272 +        Statement *stmt = node->cases()->at(i)->statement();
  1.1273 +
  1.1274 +        __ bind(&labels[i]);
  1.1275 +        stmt->accept(this);
  1.1276 +        __ jump(&join);
  1.1277 +    }
  1.1278 +
  1.1279 +    // We're done with the statement labels.
  1.1280 +    delete [] labels;
  1.1281 +
  1.1282 +    // Emit the default case.
  1.1283 +    __ bind(&def);
  1.1284 +    if (node->defaultCase())
  1.1285 +        node->defaultCase()->accept(this);
  1.1286 +
  1.1287 +    __ bind(&join);
  1.1288 +
  1.1289 +    return true;
  1.1290 +}
  1.1291 +
  1.1292 +void
  1.1293 +BytecodeCompiler::visit(SwitchStatement *node)
  1.1294 +{
  1.1295 +    node->expression()->accept(this);
  1.1296 +
  1.1297 +    if (tableswitch(node))
  1.1298 +        return;
  1.1299 +
  1.1300 +    Label join;
  1.1301 +
  1.1302 +    for (size_t i = 0; i < node->cases()->length(); i++) {
  1.1303 +        Case *c = node->cases()->at(i);
  1.1304 +
  1.1305 +        Label success, fail;
  1.1306 +        if (c->others()) {
  1.1307 +            for (size_t j = 0; j < c->others()->length(); j++) {
  1.1308 +                Expression *expr = c->others()->at(j);
  1.1309 +
  1.1310 +                __ dup();
  1.1311 +                expr->accept(this);
  1.1312 +                __ j(OP_JEQ, &success);
  1.1313 +            }
  1.1314 +        }
  1.1315 +
  1.1316 +        // The final test.
  1.1317 +        __ dup();
  1.1318 +        c->expression()->accept(this);
  1.1319 +        __ j(OP_JNE, &fail);
  1.1320 +        __ bind(&success);
  1.1321 +        c->statement()->accept(this);
  1.1322 +        __ jump(&join);
  1.1323 +        __ bind(&fail);
  1.1324 +    }
  1.1325 +
  1.1326 +    if (node->defaultCase())
  1.1327 +        node->defaultCase()->accept(this);
  1.1328 +
  1.1329 +    __ pop();
  1.1330 +    __ bind(&join);
  1.1331 +}
  1.1332 +
  1.1333 +void
  1.1334 +BytecodeCompiler::visit(FunctionStatement *node)
  1.1335 +{
  1.1336 +    if (!node->fun()->used())
  1.1337 +        return;
  1.1338 +
  1.1339 +    if (node->fun()->isNative()) {
  1.1340 +        assert(!moduleData_->natives->at(node->fun()->slot()));
  1.1341 +
  1.1342 +        Local<FunctionType> type(zone_, FunctionType::cast(node->fun()->type()));
  1.1343 +        Local<String> name(zone_, node->fun()->name());
  1.1344 +        Local<Native> native(zone_, Native::New(zone_, type, name));
  1.1345 +        if (!native)
  1.1346 +            return;
  1.1347 +
  1.1348 +        moduleData_->natives->set(zone_, node->fun()->slot(), native);
  1.1349 +        return;
  1.1350 +    }
  1.1351 +
  1.1352 +    // If the function has no body, then it's just a declaration.
  1.1353 +    if (!node->body()) {
  1.1354 +        assert(node->fun()->isForward() || node->fun()->isPublic());
  1.1355 +        return;
  1.1356 +    }
  1.1357 +
  1.1358 +    BytecodeCompiler child(zone_, tree_, moduleData_);
  1.1359 +    Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
  1.1360 +    if (!fun)
  1.1361 +        return;
  1.1362 +    
  1.1363 +    assert(!moduleData_->module->getFunction(node->fun()->slot()));
  1.1364 +    moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
  1.1365 +}
  1.1366 +
  1.1367 +void
  1.1368 +BytecodeCompiler::visit(FunctionTypeStatement *node)
  1.1369 +{
  1.1370 +}
  1.1371 +
  1.1372 +void
  1.1373 +BytecodeCompiler::visit(EnumStatement *node)
  1.1374 +{
  1.1375 +}
  1.1376 +
  1.1377 +void
  1.1378 +BytecodeCompiler::visit(StructureStatement *node)
  1.1379 +{
  1.1380 +}
  1.1381 +
  1.1382 +void
  1.1383 +BytecodeCompiler::visit(ArrayLiteral *node)
  1.1384 +{
  1.1385 +    // We shouldn't reach these; they're handled manually when initializing
  1.1386 +    // declared arrays.
  1.1387 +    assert(false);
  1.1388 +}
  1.1389 +
  1.1390 +void
  1.1391 +BytecodeCompiler::visit(ImportStatement *node)
  1.1392 +{
  1.1393 +}
  1.1394 +
  1.1395 +Code *
  1.1396 +BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
  1.1397 +{
  1.1398 +    // STOP doubles as RETURNVOID.
  1.1399 +    __ stop();
  1.1400 +
  1.1401 +    if (__ oom() || zone_->hasPendingException())
  1.1402 +        return NULL;
  1.1403 +
  1.1404 +    Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
  1.1405 +    if (!bytes)
  1.1406 +        return NULL;
  1.1407 +    memcpy(bytes->raw(), __ buffer(), __ length());
  1.1408 +
  1.1409 +    for (size_t i = 0; i < scope->maxContainedLocals(); i++)
  1.1410 +        assert(locals_->at(i));
  1.1411 +
  1.1412 +    Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
  1.1413 +    if (!objects)
  1.1414 +        return NULL;
  1.1415 +
  1.1416 +    for (size_t i = 0; i < __ objects()->length(); i++)
  1.1417 +        objects->set(zone_, i, *(__ objects()->at(i)));
  1.1418 +
  1.1419 +    Local<ByteArray> safepoints(zone_);
  1.1420 +
  1.1421 +    // If any stack slots hold gc pointers at potential failure points in the
  1.1422 +    // bytecode, record them now. We do this by building a list of tuples;
  1.1423 +    // each tuple contains the pc offset, and a bitset containing which stack
  1.1424 +    // slots must be scanned by the gc.
  1.1425 +    if (__ oopRecords()->length()) {
  1.1426 +        size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
  1.1427 +        size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
  1.1428 +        safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
  1.1429 +        if (!safepoints)
  1.1430 +            return NULL;
  1.1431 +
  1.1432 +        Address cursor = safepoints->raw();
  1.1433 +        for (size_t i = 0; i < __ oopRecords()->length(); i++) {
  1.1434 +            OopRecord *record = __ oopRecords()->at(i);
  1.1435 +            assert(record->depth <= __ maxStackDepth());
  1.1436 +
  1.1437 +            *reinterpret_cast<unsigned *>(cursor) = record->offset;
  1.1438 +
  1.1439 +            unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
  1.1440 +            for (unsigned i = 0; i < record->depth; i++)
  1.1441 +                bits[i / 8] |= (1 << (i % 8));
  1.1442 +
  1.1443 +            cursor += bytesPerSafepoint;
  1.1444 +        }
  1.1445 +
  1.1446 +        assert(cursor == safepoints->raw() + gcmapSize);
  1.1447 +    }
  1.1448 +
  1.1449 +    Local<ByteArray> sourcemap(zone_);
  1.1450 +    if (__ sourcemapLength()) {
  1.1451 +        sourcemap = ByteArray::New(zone_, __ sourcemapLength(), Heap::Tenure_Old);
  1.1452 +        if (!sourcemap)
  1.1453 +            return NULL;
  1.1454 +
  1.1455 +        memcpy(sourcemap->raw(), __ sourcemap(), __ sourcemapLength());
  1.1456 +    }
  1.1457 +
  1.1458 +    Local<Code> code(zone_);
  1.1459 +
  1.1460 +    code = Code::New(zone_,
  1.1461 +                     bytes,
  1.1462 +                     locals_,
  1.1463 +                     objects,
  1.1464 +                     __ maxStackDepth(),
  1.1465 +                     moduleData_->module,
  1.1466 +                     safepoints,
  1.1467 +                     sourcemap,
  1.1468 +                     lineno);
  1.1469 +    return code;
  1.1470 +}
  1.1471 +
  1.1472 +Function *
  1.1473 +BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
  1.1474 +{
  1.1475 +    // Note: No need to record a life slot here, since it's part of the Frame.
  1.1476 +    AutoEnterScope functionScope(this, node->scope());
  1.1477 +
  1.1478 +    // Set the initial line, because line mappings are deltas.
  1.1479 +    __ setFirstLine(node->pos().line);
  1.1480 +    locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
  1.1481 +
  1.1482 +    node->body()->accept(this);
  1.1483 +
  1.1484 +    unsigned nargs = node->scope()->numArguments();
  1.1485 +    Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
  1.1486 +    if (!args)
  1.1487 +        return NULL;
  1.1488 +
  1.1489 +    for (size_t i = 0; i < node->scope()->numArguments(); i++)
  1.1490 +        args->set(zone_, i, node->scope()->getArgument(i)->type());
  1.1491 +
  1.1492 +
  1.1493 +    Local<Code> code(zone_, compileCode(node->scope(), node->pos().line));
  1.1494 +    if (!code)
  1.1495 +        return NULL;
  1.1496 +
  1.1497 +    Local<FunctionType> type(zone_, FunctionType::cast(node->fun()->type()));
  1.1498 +    Local<String> name(zone_, node->fun()->name());
  1.1499 +    Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
  1.1500 +    if (!fun)
  1.1501 +        return NULL;
  1.1502 +
  1.1503 +    // If this function had a forward, export it as a named public.
  1.1504 +    if (node->fun()->isPublic()) {
  1.1505 +        assert(node->fun()->isPublic());
  1.1506 +        ScopedRoot<Function> root(fun);
  1.1507 +        if (!root)
  1.1508 +            return NULL;
  1.1509 +        if (!moduleData_->publics.append(root))
  1.1510 +            return NULL;
  1.1511 +    }
  1.1512 +
  1.1513 +#ifndef NDEBUG
  1.1514 +    Disassemble(code, stdout);
  1.1515 +#endif
  1.1516 +    
  1.1517 +    return fun;
  1.1518 +}
  1.1519 +
  1.1520 +Module *
  1.1521 +BytecodeCompiler::compile()
  1.1522 +{
  1.1523 +    AutoEnterScope scope(this, tree_->globalScope());
  1.1524 +
  1.1525 +    ModuleData moduleData;
  1.1526 +
  1.1527 +    moduleData_ = &moduleData;
  1.1528 +    moduleData_->module = Module::New(zone_, tree_->globalScope()->numFunctions());
  1.1529 +
  1.1530 +    if (!moduleData_)
  1.1531 +        return NULL;
  1.1532 +    
  1.1533 +    moduleData_->natives = FixedArray::New(zone_, tree_->globalScope()->numNatives(), Heap::Tenure_Old);
  1.1534 +    if (!moduleData_->natives)
  1.1535 +        return NULL;
  1.1536 +
  1.1537 +    for (size_t i = 0; i < tree_->statements()->length(); i++) {
  1.1538 +        Statement *statement = tree_->statements()->at(i);
  1.1539 +        statement->accept(this);
  1.1540 +    }
  1.1541 +
  1.1542 +    if (zone_->hasPendingException())
  1.1543 +        return NULL;
  1.1544 +
  1.1545 +#ifndef NDEBUG
  1.1546 +    for (size_t i = 0; i < tree_->globalScope()->numFunctions(); i++)
  1.1547 +        assert(moduleData_->module->getFunction(i));
  1.1548 +    for (size_t i = 0; i < tree_->globalScope()->numNatives(); i++)
  1.1549 +        assert(moduleData_->natives->at(i));
  1.1550 +#endif
  1.1551 +
  1.1552 +    if (moduleData_->publics.length()) {
  1.1553 +        Local<Function> fun(zone_);
  1.1554 +        Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
  1.1555 +                               Heap::Tenure_Old));
  1.1556 +        if (!list)
  1.1557 +            return NULL;
  1.1558 +
  1.1559 +        for (size_t i = 0; i < moduleData_->publics.length(); i++)
  1.1560 +            list->set(zone_, i, moduleData_->publics[i]);
  1.1561 +
  1.1562 +        moduleData_->module->setPublics(list);
  1.1563 +    }
  1.1564 +
  1.1565 +    moduleData_->module->setNatives(moduleData_->natives);
  1.1566 +
  1.1567 +    if (scope_->numEnvironmentVars()) {
  1.1568 +        Local<EnvironmentMap> globalMap(zone_, scope_->createEnvironmentMap(zone_));
  1.1569 +        if (!globalMap)
  1.1570 +            return NULL;
  1.1571 +
  1.1572 +        Local<Environment> environment(zone_, Environment::New(zone_, globalMap));
  1.1573 +        if (!environment)
  1.1574 +            return NULL;
  1.1575 +
  1.1576 +        moduleData_->module->setEnvironment(environment);
  1.1577 +    }
  1.1578 +
  1.1579 +    Local<Code> code(zone_, compileCode(tree_->globalScope(), 1));
  1.1580 +    if (!code)
  1.1581 +        return NULL;
  1.1582 +
  1.1583 +    Disassemble(code, stdout);
  1.1584 +
  1.1585 +    moduleData_->module->setCode(code);
  1.1586 +
  1.1587 +    return moduleData_->module;
  1.1588 +}