1.1 --- a/src/BytecodeCompiler.cpp Mon Sep 17 00:10:01 2012 -0700
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,1576 +0,0 @@
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 "BytecodeCompiler.h"
1.24 -#include "Scopes.h"
1.25 -#include "Modules.h"
1.26 -#include "Types.h"
1.27 -#include "Array.h"
1.28 -#include "Strings.h"
1.29 -#include "Zone.h"
1.30 -#include "Environments.h"
1.31 -#include "Box.h"
1.32 -#include "Heap-inl.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, 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 (node->postDimensions()) {
1.1008 - for (size_t i = 0; i < node->postDimensions()->length(); i++) {
1.1009 - Expression *expr = node->postDimensions()->at(i);
1.1010 - if (expr)
1.1011 - expr->accept(this);
1.1012 - else
1.1013 - __ int_(0);
1.1014 - }
1.1015 - __ newarray(OP_NEWSIZED, map, tenure);
1.1016 - } else {
1.1017 - __ newarray(OP_NEWEMPTY, map, tenure);
1.1018 - }
1.1019 - }
1.1020 - } else if (type->isStruct()) {
1.1021 - Local<StructMap> map(zone_, StructMap::cast(type->newMap()));
1.1022 -
1.1023 - // Because structs can contain arrays, any sort of composition
1.1024 - // triggers non-LIFO allocation. This is just for correctness.
1.1025 - // We could do better by:
1.1026 - // (1) Limiting to structs that just (recursively) contain arrays,
1.1027 - // (2) Swap Stack for Default tenure in Struct::New
1.1028 - // (3) JIT analysis
1.1029 - if (var->scope()->kind() == Scope::GLOBAL)
1.1030 - __ newstruct(map, Heap::Tenure_Old);
1.1031 - else if (var->needsHeapAllocation() || map->composed())
1.1032 - __ newstruct(map, Heap::Tenure_Default);
1.1033 - else
1.1034 - __ newstruct(map, Heap::Tenure_Stack);
1.1035 - } else {
1.1036 - if (node->initialization()) {
1.1037 - node->initialization()->accept(this);
1.1038 - } else {
1.1039 - if (type->isInt32OrEnum() || type->isBool()) {
1.1040 - __ int_(0);
1.1041 - } else {
1.1042 - assert(type->isFloat());
1.1043 - __ float_(0);
1.1044 - }
1.1045 - }
1.1046 - }
1.1047 -
1.1048 - if (var->location() == Variable::STACK) {
1.1049 - __ setlocal(var);
1.1050 - locals_->set(zone_, var->slot(), var->type());
1.1051 - } else {
1.1052 - assert(var->location() == Variable::ENVIRONMENT);
1.1053 - setEnvSlot(var);
1.1054 - }
1.1055 -
1.1056 - __ pop();
1.1057 -}
1.1058 -
1.1059 -void
1.1060 -BytecodeCompiler::visit(CallExpression *node)
1.1061 -{
1.1062 - Local<Type> funType(zone_, node->callee()->type());
1.1063 -
1.1064 - // Sniff out natives, which have a specific opcode and are guaranteed to
1.1065 - // be called via name proxy.
1.1066 - NamedFunction *native = NULL;
1.1067 - if (funType->isNative())
1.1068 - native = node->callee()->toNameProxy()->binding()->toNamedFunction();
1.1069 -
1.1070 - Local<Type> given(zone_);
1.1071 - for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
1.1072 - Expression *arg = node->arguments()->at(i);
1.1073 -
1.1074 - given = arg->type();
1.1075 -
1.1076 - // We need to compute a reference if the parameter was in the form:
1.1077 - // f(&a)
1.1078 - // Note this form does not allow: f({})
1.1079 - //
1.1080 - // We also need to compute references for all variadic native
1.1081 - // arguments, but arrays and references are already in the
1.1082 - // appropriate form.
1.1083 - bool mustPushReference = false;
1.1084 - if (i >= funType->parameters()->length()) {
1.1085 - assert(funType->isNative() && funType->isNativeVariadic());
1.1086 - mustPushReference = !given->isArray() && !given->isReference();
1.1087 - } else if (funType->parameterAt(i)->isReference()) {
1.1088 - mustPushReference = !given->isReference();
1.1089 - }
1.1090 -
1.1091 - // If a native is passed to a native, it must only be one level deep.
1.1092 - assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
1.1093 -
1.1094 - if (mustPushReference) {
1.1095 - if (arg->isNameProxy()) {
1.1096 - // :TODO: test with functions and globals
1.1097 - // Compute a reference to the name.
1.1098 - Variable *var = arg->toNameProxy()->binding()->toVariable();
1.1099 - __ note_position(node->pos());
1.1100 - __ newref(var);
1.1101 - } else if (arg->isFieldExpression()) {
1.1102 - FieldExpression *expr = arg->toFieldExpression();
1.1103 - expr->left()->accept(this);
1.1104 - __ note_position(expr->pos());
1.1105 - __ fieldref_lifo(expr->fieldIndex());
1.1106 - } else {
1.1107 - // We don't know how to, or can't, build a direct reference to
1.1108 - // this type. Make an indirect one, by taking the top of the
1.1109 - // stack and boxing it up.
1.1110 - arg->accept(this);
1.1111 - __ note_position(node->pos());
1.1112 - __ slotref_lifo();
1.1113 - }
1.1114 - } else {
1.1115 - arg->accept(this);
1.1116 - }
1.1117 - }
1.1118 -
1.1119 - unsigned argc = node->arguments()->length();
1.1120 -
1.1121 - // If there are missing arguments, then we're not done and have to push
1.1122 - // default parameters.
1.1123 - Local<Box> box(zone_);
1.1124 - Local<Array> array(zone_);
1.1125 - Local<ArrayMap> map(zone_);
1.1126 - for (size_t i = node->arguments()->length(); i < funType->parameters()->length(); i++) {
1.1127 - box = Box::cast(funType->defaults()->at(i));
1.1128 -
1.1129 - if (box->type()->isPod()) {
1.1130 - if (box->type()->pod() == PrimitiveType_Int32)
1.1131 - __ int_(box->toInt32());
1.1132 - else if (box->type()->pod() == PrimitiveType_Float)
1.1133 - __ float_(box->toFloat());
1.1134 - else
1.1135 - assert(false);
1.1136 -
1.1137 - if (funType->parameterAt(i)->isReference()) {
1.1138 - __ note_position(node->pos());
1.1139 - __ slotref_lifo();
1.1140 - }
1.1141 - } else {
1.1142 - assert(box->type()->isArray());
1.1143 -
1.1144 - array = Array::cast(box->toObject());
1.1145 - if (funType->parameterAt(i)->isConst()) {
1.1146 - __ object(array);
1.1147 - } else {
1.1148 - // We need to copy the array since it's mutable. Note that
1.1149 - // although COPYARRAY returns its left-hand side, this may
1.1150 - // change in the future, we do the same thing and dupe the
1.1151 - // newly allocated array.
1.1152 - map = ArrayMap::cast(array->map());
1.1153 -
1.1154 - // Natives cannot escape array references, so we can allocate
1.1155 - // them on the LIFO stack.
1.1156 - if (funType->isNative())
1.1157 - __ newarray(OP_NEWFIXED, map, Heap::Tenure_Stack);
1.1158 - else
1.1159 - __ newarray(OP_NEWFIXED, map, Heap::Tenure_Default);
1.1160 - __ dup();
1.1161 - __ object(array);
1.1162 - __ copyarray();
1.1163 - __ pop();
1.1164 - }
1.1165 - }
1.1166 -
1.1167 - argc++;
1.1168 - }
1.1169 -
1.1170 - __ note_position(node->pos());
1.1171 - if (native) {
1.1172 - __ callnative(native->slot(), argc);
1.1173 - __ drop(argc);
1.1174 - } else {
1.1175 - node->callee()->accept(this);
1.1176 - __ call(funType);
1.1177 - __ drop(argc + 1);
1.1178 - }
1.1179 -}
1.1180 -
1.1181 -void
1.1182 -BytecodeCompiler::visit(TernaryExpression *node)
1.1183 -{
1.1184 - Label success, failure, join;
1.1185 -
1.1186 - visitForTest(node->condition(), &success, &failure, &success);
1.1187 - __ bind(&success);
1.1188 - node->left()->accept(this);
1.1189 - __ drop(1);
1.1190 - __ jump(&join);
1.1191 - __ bind(&failure);
1.1192 - node->right()->accept(this);
1.1193 - __ bind(&join);
1.1194 -}
1.1195 -
1.1196 -void
1.1197 -BytecodeCompiler::visit(IfStatement *node)
1.1198 -{
1.1199 - Label join;
1.1200 - if (!node->ifFalse()) {
1.1201 - Label success;
1.1202 -
1.1203 - visitForTest(node->condition(), &success, &join, &success);
1.1204 - __ bind(&success);
1.1205 - node->ifTrue()->accept(this);
1.1206 - } else {
1.1207 - Label success, next;
1.1208 -
1.1209 - visitForTest(node->condition(), &success, &next, &success);
1.1210 - __ bind(&success);
1.1211 - node->ifTrue()->accept(this);
1.1212 - __ jump(&join);
1.1213 - __ bind(&next);
1.1214 - node->ifFalse()->accept(this);
1.1215 - }
1.1216 -
1.1217 - __ bind(&join);
1.1218 -}
1.1219 -
1.1220 -bool
1.1221 -BytecodeCompiler::tableswitch(SwitchStatement *node)
1.1222 -{
1.1223 - CaseValueList *values = node->caseValueList();
1.1224 -
1.1225 - if (values->length() < 3)
1.1226 - return false;
1.1227 -
1.1228 - // Find the delta between the largest and smallest value.
1.1229 - int hi = values->at(values->length() - 1).box.toInt();
1.1230 - int lo = values->at(0).box.toInt();
1.1231 - assert(hi > lo);
1.1232 -
1.1233 - unsigned tablesize = TableSwitchEntries(lo, hi);
1.1234 - if (tablesize > MAX_TABLESWITCH_ENTRIES)
1.1235 - return false;
1.1236 -
1.1237 - Label def, join;
1.1238 -
1.1239 - // Create the list of labels that each statement will bind to.
1.1240 - Label *labels = new Label[node->cases()->length()];
1.1241 -
1.1242 - // Create the table of labels we'll use for each case.
1.1243 - Label **table = new Label *[tablesize];
1.1244 -
1.1245 - // Link all cases, by default, to the default label.
1.1246 - for (size_t i = 0; i < tablesize; i++)
1.1247 - table[i] = &def;
1.1248 -
1.1249 - // Now patch actual cases to their correct labels.
1.1250 - for (size_t i = 0; i < values->length(); i++) {
1.1251 - CaseValue &v = values->at(i);
1.1252 - assert(v.statement < node->cases()->length());
1.1253 -
1.1254 - unsigned index = unsigned(v.box.toInt() - lo);
1.1255 - assert(index < tablesize);
1.1256 -
1.1257 - table[index] = &labels[v.statement];
1.1258 - }
1.1259 -
1.1260 - // Emit the tableswitch opcode and the jump table.
1.1261 - __ tableswitch(lo, hi, &def, table);
1.1262 -
1.1263 - // We're done with the jump table now.
1.1264 - delete [] table;
1.1265 -
1.1266 - // Emit each statement.
1.1267 - for (size_t i = 0; i < node->cases()->length(); i++) {
1.1268 - Statement *stmt = node->cases()->at(i)->statement();
1.1269 -
1.1270 - __ bind(&labels[i]);
1.1271 - stmt->accept(this);
1.1272 - __ jump(&join);
1.1273 - }
1.1274 -
1.1275 - // We're done with the statement labels.
1.1276 - delete [] labels;
1.1277 -
1.1278 - // Emit the default case.
1.1279 - __ bind(&def);
1.1280 - if (node->defaultCase())
1.1281 - node->defaultCase()->accept(this);
1.1282 -
1.1283 - __ bind(&join);
1.1284 -
1.1285 - return true;
1.1286 -}
1.1287 -
1.1288 -void
1.1289 -BytecodeCompiler::visit(SwitchStatement *node)
1.1290 -{
1.1291 - node->expression()->accept(this);
1.1292 -
1.1293 - if (tableswitch(node))
1.1294 - return;
1.1295 -
1.1296 - Label join;
1.1297 -
1.1298 - for (size_t i = 0; i < node->cases()->length(); i++) {
1.1299 - Case *c = node->cases()->at(i);
1.1300 -
1.1301 - Label success, fail;
1.1302 - if (c->others()) {
1.1303 - for (size_t j = 0; j < c->others()->length(); j++) {
1.1304 - Expression *expr = c->others()->at(j);
1.1305 -
1.1306 - __ dup();
1.1307 - expr->accept(this);
1.1308 - __ j(OP_JEQ, &success);
1.1309 - }
1.1310 - }
1.1311 -
1.1312 - // The final test.
1.1313 - __ dup();
1.1314 - c->expression()->accept(this);
1.1315 - __ j(OP_JNE, &fail);
1.1316 - __ bind(&success);
1.1317 - c->statement()->accept(this);
1.1318 - __ jump(&join);
1.1319 - __ bind(&fail);
1.1320 - }
1.1321 -
1.1322 - if (node->defaultCase())
1.1323 - node->defaultCase()->accept(this);
1.1324 -
1.1325 - __ pop();
1.1326 - __ bind(&join);
1.1327 -}
1.1328 -
1.1329 -void
1.1330 -BytecodeCompiler::visit(FunctionStatement *node)
1.1331 -{
1.1332 - if (!node->fun()->used())
1.1333 - return;
1.1334 -
1.1335 - if (node->fun()->isNative()) {
1.1336 - assert(!moduleData_->natives->at(node->fun()->slot()));
1.1337 -
1.1338 - Local<Type> type(zone_, node->fun()->type());
1.1339 - Local<String> name(zone_, node->fun()->name());
1.1340 - Local<Native> native(zone_, Native::New(zone_, type, name));
1.1341 - if (!native)
1.1342 - return;
1.1343 -
1.1344 - moduleData_->natives->set(zone_, node->fun()->slot(), native);
1.1345 - return;
1.1346 - }
1.1347 -
1.1348 - // If the function has no body, then it's just a declaration.
1.1349 - if (!node->body()) {
1.1350 - assert(node->fun()->isForward() || node->fun()->isPublic());
1.1351 - return;
1.1352 - }
1.1353 -
1.1354 - BytecodeCompiler child(zone_, tree_, moduleData_);
1.1355 - Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
1.1356 - if (!fun)
1.1357 - return;
1.1358 -
1.1359 - assert(!moduleData_->module->getFunction(node->fun()->slot()));
1.1360 - moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
1.1361 -}
1.1362 -
1.1363 -void
1.1364 -BytecodeCompiler::visit(FunctionTypeStatement *node)
1.1365 -{
1.1366 -}
1.1367 -
1.1368 -void
1.1369 -BytecodeCompiler::visit(EnumStatement *node)
1.1370 -{
1.1371 -}
1.1372 -
1.1373 -void
1.1374 -BytecodeCompiler::visit(StructureStatement *node)
1.1375 -{
1.1376 -}
1.1377 -
1.1378 -void
1.1379 -BytecodeCompiler::visit(ArrayLiteral *node)
1.1380 -{
1.1381 - // We shouldn't reach these; they're handled manually when initializing
1.1382 - // declared arrays.
1.1383 - assert(false);
1.1384 -}
1.1385 -
1.1386 -Code *
1.1387 -BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
1.1388 -{
1.1389 - // STOP doubles as RETURNVOID.
1.1390 - __ stop();
1.1391 -
1.1392 - if (__ oom() || zone_->hasPendingException())
1.1393 - return NULL;
1.1394 -
1.1395 - Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
1.1396 - if (!bytes)
1.1397 - return NULL;
1.1398 - memcpy(bytes->raw(), __ buffer(), __ length());
1.1399 -
1.1400 - for (size_t i = 0; i < scope->maxContainedLocals(); i++)
1.1401 - assert(locals_->at(i));
1.1402 -
1.1403 - Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
1.1404 - if (!objects)
1.1405 - return NULL;
1.1406 -
1.1407 - for (size_t i = 0; i < __ objects()->length(); i++)
1.1408 - objects->set(zone_, i, *(__ objects()->at(i)));
1.1409 -
1.1410 - Local<ByteArray> safepoints(zone_);
1.1411 -
1.1412 - // If any stack slots hold gc pointers at potential failure points in the
1.1413 - // bytecode, record them now. We do this by building a list of tuples;
1.1414 - // each tuple contains the pc offset, and a bitset containing which stack
1.1415 - // slots must be scanned by the gc.
1.1416 - if (__ oopRecords()->length()) {
1.1417 - size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
1.1418 - size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
1.1419 - safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
1.1420 - if (!safepoints)
1.1421 - return NULL;
1.1422 -
1.1423 - Address cursor = safepoints->raw();
1.1424 - for (size_t i = 0; i < __ oopRecords()->length(); i++) {
1.1425 - OopRecord *record = __ oopRecords()->at(i);
1.1426 - assert(record->depth <= __ maxStackDepth());
1.1427 -
1.1428 - *reinterpret_cast<unsigned *>(cursor) = record->offset;
1.1429 -
1.1430 - unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
1.1431 - for (unsigned i = 0; i < record->depth; i++)
1.1432 - bits[i / 8] |= (1 << (i % 8));
1.1433 -
1.1434 - cursor += bytesPerSafepoint;
1.1435 - }
1.1436 -
1.1437 - assert(cursor == safepoints->raw() + gcmapSize);
1.1438 - }
1.1439 -
1.1440 - Local<ByteArray> sourcemap(zone_);
1.1441 - if (__ sourcemapLength()) {
1.1442 - sourcemap = ByteArray::New(zone_, __ sourcemapLength(), Heap::Tenure_Old);
1.1443 - if (!sourcemap)
1.1444 - return NULL;
1.1445 -
1.1446 - memcpy(sourcemap->raw(), __ sourcemap(), __ sourcemapLength());
1.1447 - }
1.1448 -
1.1449 - Local<Code> code(zone_);
1.1450 -
1.1451 - code = Code::New(zone_,
1.1452 - bytes,
1.1453 - locals_,
1.1454 - objects,
1.1455 - __ maxStackDepth(),
1.1456 - moduleData_->module,
1.1457 - safepoints,
1.1458 - sourcemap,
1.1459 - lineno);
1.1460 - return code;
1.1461 -}
1.1462 -
1.1463 -Function *
1.1464 -BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
1.1465 -{
1.1466 - // Note: No need to record a life slot here, since it's part of the Frame.
1.1467 - AutoEnterScope functionScope(this, node->scope());
1.1468 -
1.1469 - // Set the initial line, because line mappings are deltas.
1.1470 - __ setFirstLine(node->pos().line);
1.1471 - locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
1.1472 -
1.1473 - node->body()->accept(this);
1.1474 -
1.1475 - unsigned nargs = node->scope()->numArguments();
1.1476 - Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
1.1477 - if (!args)
1.1478 - return NULL;
1.1479 -
1.1480 - for (size_t i = 0; i < node->scope()->numArguments(); i++)
1.1481 - args->set(zone_, i, node->scope()->getArgument(i)->type());
1.1482 -
1.1483 -
1.1484 - Local<Code> code(zone_, compileCode(node->scope(), node->pos().line));
1.1485 - if (!code)
1.1486 - return NULL;
1.1487 -
1.1488 - Local<Type> type(zone_, node->fun()->type());
1.1489 - Local<String> name(zone_, node->fun()->name());
1.1490 - Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
1.1491 - if (!fun)
1.1492 - return NULL;
1.1493 -
1.1494 - // If this function had a forward, export it as a named public.
1.1495 - if (node->fun()->isPublic()) {
1.1496 - assert(node->fun()->isPublic());
1.1497 - ScopedRoot<Function> root(fun);
1.1498 - if (!root)
1.1499 - return NULL;
1.1500 - if (!moduleData_->publics.append(root))
1.1501 - return NULL;
1.1502 - }
1.1503 -
1.1504 -#ifndef NDEBUG
1.1505 - Disassemble(code, stdout);
1.1506 -#endif
1.1507 -
1.1508 - return fun;
1.1509 -}
1.1510 -
1.1511 -Module *
1.1512 -BytecodeCompiler::compile()
1.1513 -{
1.1514 - AutoEnterScope scope(this, tree_->scope());
1.1515 -
1.1516 - ModuleData moduleData;
1.1517 -
1.1518 - moduleData_ = &moduleData;
1.1519 - moduleData_->module = Module::New(zone_, tree_->scope()->numFunctions());
1.1520 -
1.1521 - if (!moduleData_)
1.1522 - return NULL;
1.1523 -
1.1524 - moduleData_->natives = FixedArray::New(zone_, tree_->scope()->numNatives(), Heap::Tenure_Old);
1.1525 - if (!moduleData_->natives)
1.1526 - return NULL;
1.1527 -
1.1528 - for (size_t i = 0; i < tree_->statements()->length(); i++) {
1.1529 - Statement *statement = tree_->statements()->at(i);
1.1530 - statement->accept(this);
1.1531 - }
1.1532 -
1.1533 - if (zone_->hasPendingException())
1.1534 - return NULL;
1.1535 -
1.1536 -#ifndef NDEBUG
1.1537 - for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
1.1538 - assert(moduleData_->module->getFunction(i));
1.1539 - for (size_t i = 0; i < tree_->scope()->numNatives(); i++)
1.1540 - assert(moduleData_->natives->at(i));
1.1541 -#endif
1.1542 -
1.1543 - if (moduleData_->publics.length()) {
1.1544 - Local<Function> fun(zone_);
1.1545 - Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
1.1546 - Heap::Tenure_Old));
1.1547 - if (!list)
1.1548 - return NULL;
1.1549 -
1.1550 - for (size_t i = 0; i < moduleData_->publics.length(); i++)
1.1551 - list->set(zone_, i, moduleData_->publics[i]);
1.1552 -
1.1553 - moduleData_->module->setPublics(list);
1.1554 - }
1.1555 -
1.1556 - moduleData_->module->setNatives(moduleData_->natives);
1.1557 -
1.1558 - if (scope_->numEnvironmentVars()) {
1.1559 - Local<EnvironmentMap> globalMap(zone_, scope_->createEnvironmentMap(zone_));
1.1560 - if (!globalMap)
1.1561 - return NULL;
1.1562 -
1.1563 - Local<Environment> environment(zone_, Environment::New(zone_, globalMap));
1.1564 - if (!environment)
1.1565 - return NULL;
1.1566 -
1.1567 - moduleData_->module->setEnvironment(environment);
1.1568 - }
1.1569 -
1.1570 - Local<Code> code(zone_, compileCode(tree_->scope(), 1));
1.1571 - if (!code)
1.1572 - return NULL;
1.1573 -
1.1574 - Disassemble(code, stdout);
1.1575 -
1.1576 - moduleData_->module->setCode(code);
1.1577 -
1.1578 - return moduleData_->module;
1.1579 -}