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 +}