1.1 --- a/jitcraft/BytecodeCompiler.cpp Tue Jul 24 23:53:34 2012 -0700
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,1096 +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 "BytecodeCompiler.h"
1.23 -#include "Scopes.h"
1.24 -#include "Modules.h"
1.25 -#include "Types.h"
1.26 -#include "Array.h"
1.27 -#include "Strings.h"
1.28 -#include "Zone.h"
1.29 -#include "Environments.h"
1.30 -#include "Heap-inl.h"
1.31 -
1.32 -using namespace ke;
1.33 -
1.34 -typedef BytecodeEmitter::Label Label;
1.35 -
1.36 -#define __ emitter_.
1.37 -
1.38 -BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
1.39 - : zone_(zone),
1.40 - tree_(tree),
1.41 - emitter_(zone->pool()),
1.42 - moduleData_(module),
1.43 - locals_(NULL),
1.44 - scope_(NULL),
1.45 - loop_(NULL)
1.46 -{
1.47 -}
1.48 -
1.49 -static inline TokenKind
1.50 -ToCompare(Expression *expr)
1.51 -{
1.52 - if (expr->isBinaryExpression()) {
1.53 - BinaryExpression *b = expr->toBinaryExpression();
1.54 - if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
1.55 - return b->token();
1.56 - } else if (expr->isUnaryExpression()) {
1.57 - UnaryExpression *u = expr->toUnaryExpression();
1.58 - if (u->token() == TOK_NOT)
1.59 - return TOK_NOT;
1.60 - }
1.61 - return TOK_EOF;
1.62 -}
1.63 -
1.64 -static inline Opcode
1.65 -CompareTokenToJump(TokenKind kind)
1.66 -{
1.67 - switch (kind) {
1.68 - case TOK_EQUALS:
1.69 - return OP_JEQ;
1.70 - case TOK_NOTEQUALS:
1.71 - return OP_JNE;
1.72 - case TOK_GT:
1.73 - return OP_JG;
1.74 - case TOK_GE:
1.75 - return OP_JGE;
1.76 - case TOK_LT:
1.77 - return OP_JL;
1.78 - default:
1.79 - assert(kind == TOK_LE);
1.80 - return OP_JLE;
1.81 - }
1.82 -}
1.83 -
1.84 -static inline Opcode
1.85 -TokenToOpcode(TokenKind kind)
1.86 -{
1.87 - switch (kind) {
1.88 - case TOK_PLUS:
1.89 - return OP_ADD;
1.90 - case TOK_MINUS:
1.91 - return OP_SUB;
1.92 - case TOK_STAR:
1.93 - return OP_MUL;
1.94 - case TOK_SLASH:
1.95 - return OP_DIV;
1.96 - case TOK_PERCENT:
1.97 - return OP_MOD;
1.98 - case TOK_SHR:
1.99 - return OP_SHR;
1.100 - case TOK_USHR:
1.101 - return OP_USHR;
1.102 - case TOK_SHL:
1.103 - return OP_SHL;
1.104 - case TOK_BITAND:
1.105 - return OP_BITAND;
1.106 - case TOK_BITOR:
1.107 - return OP_BITOR;
1.108 - case TOK_GT:
1.109 - return OP_GT;
1.110 - case TOK_GE:
1.111 - return OP_GE;
1.112 - case TOK_LT:
1.113 - return OP_LT;
1.114 - case TOK_LE:
1.115 - return OP_LE;
1.116 - case TOK_EQUALS:
1.117 - return OP_EQ;
1.118 - case TOK_NOTEQUALS:
1.119 - return OP_NE;
1.120 - default:
1.121 - assert(kind == TOK_BITXOR);
1.122 - return OP_BITXOR;
1.123 - }
1.124 -}
1.125 -
1.126 -void
1.127 -BytecodeCompiler::recordLifoSlot(Scope *scope)
1.128 -{
1.129 - if (!scope)
1.130 - return;
1.131 -
1.132 - if (Variable *var = scope->lifoSlot()) {
1.133 - locals_->set(zone_, var->slot(), var->type());
1.134 - __ savelifo(var->slot());
1.135 - }
1.136 -}
1.137 -
1.138 -void
1.139 -BytecodeCompiler::unwindTo(Scope *scope)
1.140 -{
1.141 - // Note: we only need to unwind to the outermost scope's LIFO slot.
1.142 - Variable *var = NULL;
1.143 - for (Scope *current = scope_; current != scope; current = current->enclosing()) {
1.144 - if (Variable *slot = current->lifoSlot())
1.145 - var = slot;
1.146 - }
1.147 -
1.148 - if (var)
1.149 - __ unwindlifo(var->slot());
1.150 -}
1.151 -
1.152 -void
1.153 -BytecodeCompiler::visit(NameProxy *name)
1.154 -{
1.155 - switch (name->binding()->kind()) {
1.156 - case BoundName::VARIABLE:
1.157 - {
1.158 - Variable *var = name->binding()->toVariable();
1.159 -
1.160 - if (var->location() == Variable::STACK) {
1.161 - __ getlocal(var);
1.162 - assert(!name->type()->isReference());
1.163 - } else if (var->location() == Variable::ENVIRONMENT) {
1.164 - getEnvSlot(var);
1.165 - } else {
1.166 - assert(var->location() == Variable::PARAMETER);
1.167 - __ getarg(var);
1.168 -
1.169 - // If this argument is actually a reference, dereference it now.
1.170 - if (var->type()->isReference())
1.171 - __ getref(var->type()->contained()->primitive());
1.172 - }
1.173 - break;
1.174 - }
1.175 -
1.176 - case BoundName::FUNCTION:
1.177 - {
1.178 - NamedFunction *fun = name->binding()->toNamedFunction();
1.179 - __ module();
1.180 - __ getmodule_fn(fun->slot());
1.181 - break;
1.182 - }
1.183 -
1.184 - default:
1.185 - {
1.186 - NamedConstant *constant = name->binding()->toNamedConstant();
1.187 - __ int_(constant->value().toInt());
1.188 - break;
1.189 - }
1.190 - }
1.191 -}
1.192 -
1.193 -void
1.194 -BytecodeCompiler::visit(ExpressionStatement *node)
1.195 -{
1.196 - // Expressions leave their value on the top of the stack, so we make sure
1.197 - // to balance the stack if they're used as a statement.
1.198 - node->expression()->accept(this);
1.199 - if (!node->expression()->type()->isVoid())
1.200 - __ pop();
1.201 -}
1.202 -
1.203 -void
1.204 -BytecodeCompiler::visit(Assignment *node)
1.205 -{
1.206 - // The first step is three sub-steps:
1.207 - //
1.208 - // (1) Bind the left-hand side.
1.209 - // -- If a cumulative operation (+=, etc):
1.210 - // (2) Save a copy of the binding on the stack.
1.211 - // (3) Dereference the binding to get a value.
1.212 - //
1.213 - if (node->lvalue()->isNameProxy()) {
1.214 - NameProxy *proxy = node->lvalue()->toNameProxy();
1.215 - Variable *var = proxy->binding()->toVariable();
1.216 -
1.217 - // Bind.
1.218 - if (var->type()->isReference() || var->type()->isArray())
1.219 - __ get(var);
1.220 -
1.221 - // Get the value if needed.
1.222 - if (node->token() != TOK_ASSIGN) {
1.223 - // += etc is not allowed on arrays.
1.224 - assert(!var->type()->isArray());
1.225 -
1.226 - if (var->type()->isReference()) {
1.227 - __ dup();
1.228 - __ getref(var->type()->contained()->primitive());
1.229 - } else {
1.230 - __ get(var);
1.231 - }
1.232 - }
1.233 - } else {
1.234 - IndexExpression *index = node->lvalue()->toIndexExpression();
1.235 - __ note_position(index->pos());
1.236 -
1.237 - // Note: Eventually, watch out for a whole here. An expression like:
1.238 - //
1.239 - // (a[4] = (5, a = []))
1.240 - //
1.241 - // Could shrink array, so we need to either bind a[i] to a Reference,
1.242 - // or keep the bounds check near the set. This is just a semantic
1.243 - // decision.
1.244 - index->left()->accept(this);
1.245 - index->right()->accept(this);
1.246 -
1.247 - if (node->token() != TOK_ASSIGN) {
1.248 - __ dup2();
1.249 - __ bounds();
1.250 - if (node->type()->isArray())
1.251 - __ getarray_o();
1.252 - else
1.253 - __ getarray(node->type()->primitive());
1.254 - }
1.255 - }
1.256 -
1.257 - if (node->token() == TOK_ASSIGN) {
1.258 - node->expression()->accept(this);
1.259 - } else {
1.260 - visitForALU(node->type(), node->expression());
1.261 -
1.262 - TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
1.263 - __ note_position(node->pos());
1.264 - __ binary(TokenToOpcode(alu));
1.265 - }
1.266 -
1.267 - // Emit the store.
1.268 - if (node->expression()->type()->isArray()) {
1.269 - // Unlike references, which can only be computed from a NamePRoxy,
1.270 - // arrays can be computed from multiple lvalue types.
1.271 - __ note_position(node->pos());
1.272 - __ arraycopy();
1.273 - } else if (node->lvalue()->isNameProxy()) {
1.274 - NameProxy *proxy = node->lvalue()->toNameProxy();
1.275 - Variable *var = proxy->binding()->toVariable();
1.276 -
1.277 - if (var->type()->isReference())
1.278 - __ setref(var->type()->contained()->primitive());
1.279 - else
1.280 - __ set(var);
1.281 - } else {
1.282 - IndexExpression *index = node->lvalue()->toIndexExpression();
1.283 - // :TODO: get rid of the BOUNDS instruction, embed it in g/setarray*?
1.284 - // We can't emit it here because the stack is slightly out of position.
1.285 - // __ bounds();
1.286 - __ setarray(index->left()->type()->contained()->primitive());
1.287 - }
1.288 -}
1.289 -
1.290 -void
1.291 -BytecodeCompiler::visit(IncDecExpression *node)
1.292 -{
1.293 - // In the postfix case, the logic looks like:
1.294 - // (1) Bind -> REF
1.295 - // (2) Dup -> REF REF
1.296 - // (3) Fetch -> REF VAL
1.297 - // (4) Swap -> VAL REF
1.298 - // (5) Pick -> VAL REF VAL
1.299 - // (6) Add -> VAL REF VAL+1
1.300 - // (7) Store -> VAL VAL+1
1.301 - // (8) Drop -> VAL
1.302 - //
1.303 - // In the prefix case, the logic looks like:
1.304 - // (1) Bind -> REF
1.305 - // (2) Dup -> REF REF
1.306 - // (3) Fetch -> REF VAL
1.307 - // --
1.308 - // --
1.309 - // (6) Add -> REF VAL+1
1.310 - // (7) Store -> VAL+1
1.311 - // --
1.312 - //
1.313 - // This is squirrely enough such that we don't bother sharing too much
1.314 - // with the above.
1.315 - //
1.316 - // Note: We simulate a "Pick" operation with a dup2+pop.
1.317 -
1.318 - // This is steps (1) to (5).
1.319 - Expression *expr = node->expression();
1.320 - if (expr->isNameProxy()) {
1.321 - NameProxy *proxy = expr->toNameProxy();
1.322 - Variable *var = proxy->binding()->toVariable();
1.323 -
1.324 - // Bind.
1.325 - if (var->type()->isReference() || var->type()->isArray())
1.326 - __ get(var);
1.327 -
1.328 - // Dup and fetch.
1.329 - if (var->type()->isReference()) {
1.330 - __ dup();
1.331 - __ getref(node->type()->primitive());
1.332 - if (node->postfix()) {
1.333 - __ swap();
1.334 - __ pick2();
1.335 - }
1.336 - } else {
1.337 - assert(!var->type()->isArray());
1.338 - __ get(var);
1.339 - if (node->postfix())
1.340 - __ dup();
1.341 - }
1.342 - } else {
1.343 - IndexExpression *index = expr->toIndexExpression();
1.344 - __ note_position(index->pos());
1.345 -
1.346 - index->left()->accept(this);
1.347 - index->right()->accept(this);
1.348 -
1.349 - assert(!node->type()->isArray());
1.350 - __ bounds();
1.351 - __ dup2();
1.352 - __ getarray(node->type()->primitive());
1.353 -
1.354 - if (node->postfix()) {
1.355 - // The stack looks like this now:
1.356 - // ARRAY INDEX VALUE
1.357 - //
1.358 - // So we must use a PICK operation to rotate the stack into position.
1.359 - __ roll3(); // INDEX VALUE ARRAY
1.360 - __ roll3(); // VALUE ARRAY INDEX
1.361 - __ pick3(); // VALUE ARRAY INDEX VALUE
1.362 - }
1.363 - }
1.364 -
1.365 - // Perform step (6).
1.366 - if (node->type()->isFloat()) {
1.367 - __ float_(1.0);
1.368 - } else {
1.369 - assert(node->type()->isInt32());
1.370 - __ int_(1);
1.371 - }
1.372 -
1.373 - __ note_position(node->pos());
1.374 - if (node->token() == TOK_INCREMENT)
1.375 - __ binary(OP_ADD);
1.376 - else
1.377 - __ binary(OP_SUB);
1.378 -
1.379 - // Perform step (7).
1.380 - if (expr->isNameProxy()) {
1.381 - NameProxy *proxy = expr->toNameProxy();
1.382 - Variable *var = proxy->binding()->toVariable();
1.383 -
1.384 - if (var->type()->isReference())
1.385 - __ setref(node->type()->primitive());
1.386 - else
1.387 - __ set(var);
1.388 - } else {
1.389 - __ setarray(node->type()->primitive());
1.390 - }
1.391 -
1.392 - // Perform step (8).
1.393 - if (node->postfix())
1.394 - __ pop();
1.395 -}
1.396 -
1.397 -void
1.398 -BytecodeCompiler::visitForALU(Type *needed, Expression *node)
1.399 -{
1.400 - node->accept(this);
1.401 - if (needed->isFloat() && !node->type()->isFloat())
1.402 - __ cvt_i2f();
1.403 - else
1.404 - assert(needed->primitive() == node->type()->primitive());
1.405 -}
1.406 -
1.407 -static inline Type *
1.408 -GetCoercionType(TokenKind tok, Type *left, Type *right)
1.409 -{
1.410 - if (left->isFloat())
1.411 - return left;
1.412 - return right;
1.413 -}
1.414 -
1.415 -void
1.416 -BytecodeCompiler::visit(UnaryExpression *node)
1.417 -{
1.418 - switch (node->token()) {
1.419 - case TOK_MINUS:
1.420 - {
1.421 - Local<Type> type(zone_, node->expression()->type());
1.422 - node->expression()->accept(this);
1.423 -
1.424 - if (node->type()->isFloat())
1.425 - __ neg_f();
1.426 - else
1.427 - __ neg();
1.428 - break;
1.429 - }
1.430 -
1.431 - case TOK_NOT:
1.432 - {
1.433 - Local<Type> type(zone_, node->expression()->type());
1.434 - node->expression()->accept(this);
1.435 -
1.436 - if (node->type()->isFloat())
1.437 - __ not_f();
1.438 - else
1.439 - __ not_();
1.440 - break;
1.441 - }
1.442 -
1.443 - default:
1.444 - assert(node->token() == TOK_TILDE);
1.445 - node->expression()->accept(this);
1.446 - __ bitnot();
1.447 - break;
1.448 - }
1.449 -}
1.450 -
1.451 -void
1.452 -BytecodeCompiler::visit(BinaryExpression *node)
1.453 -{
1.454 - if (node->token() == TOK_AND || node->token() == TOK_OR) {
1.455 - Label success, failure, done;
1.456 - visitForTest(node, &success, &failure, &success);
1.457 - __ bind(&success);
1.458 - __ int_(1);
1.459 - __ drop(1); // Otherwise, the stack depth will be +1 too much.
1.460 - __ jump(&done);
1.461 - __ bind(&failure);
1.462 - __ int_(0);
1.463 - __ bind(&done);
1.464 - return;
1.465 - }
1.466 -
1.467 - Local<Type> leftType(zone_, node->left()->type());
1.468 - Local<Type> rightType(zone_, node->right()->type());
1.469 - Local<Type> coerce(zone_, GetCoercionType(node->token(), leftType, rightType));
1.470 -
1.471 - visitForALU(coerce, node->left());
1.472 - visitForALU(coerce, node->right());
1.473 -
1.474 - Opcode op = TokenToOpcode(node->token());
1.475 - if (node->type()->isFloat())
1.476 - op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
1.477 -
1.478 - __ note_position(node->pos());
1.479 - __ binary(op);
1.480 -}
1.481 -
1.482 -void
1.483 -BytecodeCompiler::visit(IndexExpression *node)
1.484 -{
1.485 - node->left()->accept(this);
1.486 - node->right()->accept(this);
1.487 - __ note_position(node->pos());
1.488 - __ bounds();
1.489 -
1.490 - if (node->type()->isArray())
1.491 - __ getarray_o();
1.492 - else
1.493 - __ getarray(node->type()->primitive());
1.494 -}
1.495 -
1.496 -void
1.497 -BytecodeCompiler::visit(ReturnStatement *node)
1.498 -{
1.499 - if (node->expression()) {
1.500 - node->expression()->accept(this);
1.501 - __ return_();
1.502 - } else {
1.503 - __ returnvoid();
1.504 - }
1.505 -}
1.506 -
1.507 -void
1.508 -BytecodeCompiler::visitForTest(Expression *expression,
1.509 - Label *trueBranch,
1.510 - Label *falseBranch,
1.511 - Label *fallthrough)
1.512 -{
1.513 - TokenKind token = ToCompare(expression);
1.514 - if (token == TOK_EOF || token == TOK_NOT) {
1.515 - if (token == TOK_EOF)
1.516 - expression->accept(this);
1.517 - else
1.518 - expression->toUnaryExpression()->expression()->accept(this);
1.519 -
1.520 - bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
1.521 -
1.522 - Opcode op = jumpOnTrue ? OP_JT : OP_JF;
1.523 - if (expression->type()->isFloat())
1.524 - op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
1.525 -
1.526 - if (fallthrough == falseBranch)
1.527 - __ j(op, trueBranch);
1.528 - else
1.529 - __ j(op, falseBranch);
1.530 - return;
1.531 - }
1.532 -
1.533 - BinaryExpression *binary = expression->toBinaryExpression();
1.534 -
1.535 - if (token == TOK_AND || token == TOK_OR) {
1.536 - Label next;
1.537 - if (token == TOK_AND)
1.538 - visitForTest(binary->left(), &next, falseBranch, &next);
1.539 - else
1.540 - visitForTest(binary->left(), trueBranch, &next, &next);
1.541 - __ bind(&next);
1.542 - visitForTest(binary->right(), trueBranch, falseBranch, fallthrough);
1.543 - return;
1.544 - }
1.545 -
1.546 - Opcode op = CompareTokenToJump(token);
1.547 - if (fallthrough == trueBranch)
1.548 - op = Invert(op);
1.549 -
1.550 - Local<Type> leftType(zone_, binary->left()->type());
1.551 - Local<Type> rightType(zone_, binary->right()->type());
1.552 - Local<Type> coerce(zone_, GetCoercionType(binary->token(), leftType, rightType));
1.553 -
1.554 - visitForALU(coerce, binary->left());
1.555 - visitForALU(coerce, binary->right());
1.556 - if (coerce->isFloat())
1.557 - op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
1.558 -
1.559 - if (fallthrough == trueBranch)
1.560 - __ j(op, falseBranch);
1.561 - else
1.562 - __ j(op, trueBranch);
1.563 -}
1.564 -
1.565 -void
1.566 -BytecodeCompiler::visit(ForStatement *node)
1.567 -{
1.568 - AutoEnterScope forScope(this, node->scope());
1.569 -
1.570 - recordLifoSlot(node->scope());
1.571 -
1.572 - Label join, update;
1.573 - LoopScope loop(scope_, &join, &update, &loop_);
1.574 -
1.575 - if (node->initialization())
1.576 - node->initialization()->accept(this);
1.577 -
1.578 - Label header, test;
1.579 - if (node->condition())
1.580 - __ jump(&test);
1.581 -
1.582 - __ bind(&header);
1.583 - node->body()->accept(this);
1.584 -
1.585 - __ bind(&update);
1.586 - if (node->update())
1.587 - node->update()->accept(this);
1.588 -
1.589 - if (node->condition()) {
1.590 - __ bind(&test);
1.591 - visitForTest(node->condition(), &header, &join, &join);
1.592 - } else {
1.593 - __ jump(&header);
1.594 - }
1.595 -
1.596 - __ bind(&join);
1.597 -
1.598 - if (node->scope())
1.599 - unwindTo(node->scope()->enclosing());
1.600 - assert(__ stackDepth() == 0);
1.601 -}
1.602 -
1.603 -void
1.604 -BytecodeCompiler::visit(WhileStatement *node)
1.605 -{
1.606 - Label header, join;
1.607 -
1.608 - __ bind(&header);
1.609 -
1.610 - LoopScope loop(scope_, &join, &header, &loop_);
1.611 -
1.612 - if (node->token() == TOK_WHILE) {
1.613 - Label body;
1.614 -
1.615 - visitForTest(node->condition(), &body, &join, &body);
1.616 - __ bind(&body);
1.617 - node->body()->accept(this);
1.618 - __ jump(&header);
1.619 - } else {
1.620 - node->body()->accept(this);
1.621 - visitForTest(node->condition(), &header, &join, &join);
1.622 - }
1.623 -
1.624 - __ bind(&join);
1.625 -}
1.626 -
1.627 -void
1.628 -BytecodeCompiler::visit(BreakStatement *node)
1.629 -{
1.630 - unwindTo(loop_->scope());
1.631 - __ jump(loop_->break_());
1.632 -}
1.633 -
1.634 -void
1.635 -BytecodeCompiler::visit(ContinueStatement *node)
1.636 -{
1.637 - unwindTo(loop_->scope());
1.638 - __ jump(loop_->continue_());
1.639 -}
1.640 -
1.641 -void
1.642 -BytecodeCompiler::visit(BlockStatement *node)
1.643 -{
1.644 - AutoEnterScope blockScope(this, node->scope());
1.645 -
1.646 - recordLifoSlot(node->scope());
1.647 -
1.648 - for (size_t i = 0; i < node->statements()->length(); i++) {
1.649 - Statement *statement = node->statements()->at(i);
1.650 - statement->accept(this);
1.651 - assert(__ stackDepth() == 0);
1.652 - }
1.653 -
1.654 - // We don't bother emitting an "unwind" instruction for function scopes,
1.655 - // since this is taken care of by the calling convention.
1.656 - if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
1.657 - unwindTo(node->scope()->enclosing());
1.658 -}
1.659 -
1.660 -void
1.661 -BytecodeCompiler::visit(IntegerLiteral *node)
1.662 -{
1.663 - __ int_(node->value());
1.664 -}
1.665 -
1.666 -void
1.667 -BytecodeCompiler::visit(FloatLiteral *node)
1.668 -{
1.669 - __ float_((float)node->value());
1.670 -}
1.671 -
1.672 -static inline ArrayMap *
1.673 -BuildArrayMap(Zone *zone, Handle<Type> type)
1.674 -{
1.675 - Local<ArrayMap> contained(zone);
1.676 - if (type->levels() > 1) {
1.677 - Local<Type> containedType(zone, type->contained());
1.678 - contained = BuildArrayMap(zone, containedType);
1.679 - if (!contained)
1.680 - return NULL;
1.681 - }
1.682 -
1.683 - return ArrayMap::New(zone, type, contained);
1.684 -}
1.685 -
1.686 -void
1.687 -BytecodeCompiler::visit(StringLiteral *node)
1.688 -{
1.689 - Local<Type> type(zone_, node->type());
1.690 - Local<ArrayMap> map(zone_, BuildArrayMap(zone_, type));
1.691 - if (!map)
1.692 - return;
1.693 -
1.694 - Local<Array> array(zone_, Array::New(zone_, map, node->string()->length(), Heap::Tenure_Old));
1.695 - if (!array)
1.696 - return;
1.697 -
1.698 - assert(array->nelements() >= node->string()->length());
1.699 - memcpy(array->chars(), node->string()->raw(), node->string()->length() * sizeof(char));
1.700 -
1.701 - __ note_position(node->pos());
1.702 - __ object(array);
1.703 -}
1.704 -
1.705 -void
1.706 -BytecodeCompiler::getEnvSlot(Variable *var)
1.707 -{
1.708 - assert(var->scope()->kind() == Scope::GLOBAL);
1.709 - __ getglobal(var);
1.710 -}
1.711 -
1.712 -void
1.713 -BytecodeCompiler::setEnvSlot(Variable *var)
1.714 -{
1.715 - assert(var->scope()->kind() == Scope::GLOBAL);
1.716 - __ setglobal(var);
1.717 -}
1.718 -
1.719 -void
1.720 -BytecodeCompiler::visit(VariableDeclaration *node)
1.721 -{
1.722 - Variable *var = node->variable();
1.723 -
1.724 - Local<Type> type(zone_, var->type());
1.725 - if (type->isArray()) {
1.726 - Local<ArrayMap> map(zone_, BuildArrayMap(zone_, type));
1.727 - __ note_position(node->pos());
1.728 - if (var->scope()->kind() == Scope::GLOBAL)
1.729 - __ newarray(map, Heap::Tenure_Old);
1.730 - else if (var->needsHeapAllocation())
1.731 - __ newarray(map, Heap::Tenure_Default);
1.732 - else
1.733 - __ newarray(map, Heap::Tenure_Stack);
1.734 -
1.735 - if (node->initialization()) {
1.736 - node->initialization()->accept(this);
1.737 - __ note_position(node->pos());
1.738 - __ arraycopy();
1.739 - }
1.740 - } else {
1.741 - if (node->initialization()) {
1.742 - node->initialization()->accept(this);
1.743 - } else {
1.744 - if (!node->postDimensions())
1.745 - __ int_(0);
1.746 - }
1.747 - }
1.748 -
1.749 - if (var->location() == Variable::STACK) {
1.750 - __ setlocal(var);
1.751 - locals_->set(zone_, var->slot(), var->type());
1.752 - } else {
1.753 - assert(var->location() == Variable::ENVIRONMENT);
1.754 - setEnvSlot(var);
1.755 - }
1.756 -
1.757 - __ pop();
1.758 -}
1.759 -
1.760 -void
1.761 -BytecodeCompiler::visit(CallExpression *node)
1.762 -{
1.763 - Local<Type> funType(zone_, node->callee()->type());
1.764 -
1.765 - // Sniff out natives, which have a specific opcode and are guaranteed to
1.766 - // be called via name proxy.
1.767 - NamedFunction *native = NULL;
1.768 - if (funType->isNative()) {
1.769 - native = node->callee()->toNameProxy()->binding()->toNamedFunction();
1.770 - }
1.771 -
1.772 - for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
1.773 - Expression *arg = node->arguments()->at(i);
1.774 -
1.775 - // We need to compute a reference if the parameter was in the form:
1.776 - // f(&a)
1.777 - // Note this form does not allow: f({})
1.778 - //
1.779 - // We also need to compute references for all variadic native
1.780 - // arguments, but arrays and references are already in the
1.781 - // appropriate form.
1.782 - Local<Type> given(zone_, arg->type());
1.783 - bool mustPushReference = false;
1.784 - if (i >= funType->parameters()->length()) {
1.785 - assert(funType->isNative() && funType->isNativeVariadic());
1.786 - mustPushReference = !given->isArray() && !given->isReference();
1.787 - } else if (funType->parameterAt(i)->isReference()) {
1.788 - mustPushReference = !given->isReference();
1.789 - }
1.790 -
1.791 - // If a native is passed to a native, it must only be one level deep.
1.792 - assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
1.793 -
1.794 - if (mustPushReference) {
1.795 - if (arg->isNameProxy()) {
1.796 - // :TODO: test with functions and globals
1.797 - // Compute a reference to the name.
1.798 - Variable *var = arg->toNameProxy()->binding()->toVariable();
1.799 - __ note_position(node->pos());
1.800 - __ newref(var);
1.801 - } else if (arg->isIndexExpression()) {
1.802 - IndexExpression *expr = arg->toIndexExpression();
1.803 - expr->left()->accept(this);
1.804 - expr->right()->accept(this);
1.805 - __ note_position(expr->pos());
1.806 - __ bounds();
1.807 - __ arrayref_lifo();
1.808 - } else {
1.809 - // We don't know how to, or can't, build a direct reference to
1.810 - // this type. Make an indirect one, by taking the top of the
1.811 - // stack and boxing it up.
1.812 - arg->accept(this);
1.813 - __ note_position(node->pos());
1.814 - __ slotref_lifo();
1.815 - }
1.816 - } else {
1.817 - arg->accept(this);
1.818 - }
1.819 - }
1.820 -
1.821 - __ note_position(node->pos());
1.822 - if (native) {
1.823 - __ callnative(native->slot(), node->arguments()->length());
1.824 - __ drop(node->arguments()->length());
1.825 - } else {
1.826 - node->callee()->accept(this);
1.827 - __ call(funType);
1.828 - __ drop(node->arguments()->length() + 1);
1.829 - }
1.830 -}
1.831 -
1.832 -void
1.833 -BytecodeCompiler::visit(TernaryExpression *node)
1.834 -{
1.835 - Label success, failure, join;
1.836 -
1.837 - visitForTest(node->condition(), &success, &failure, &success);
1.838 - __ bind(&success);
1.839 - node->left()->accept(this);
1.840 - __ drop(1);
1.841 - __ jump(&join);
1.842 - __ bind(&failure);
1.843 - node->right()->accept(this);
1.844 - __ bind(&join);
1.845 -}
1.846 -
1.847 -void
1.848 -BytecodeCompiler::visit(IfStatement *node)
1.849 -{
1.850 - Label join;
1.851 - if (!node->ifFalse()) {
1.852 - Label success;
1.853 -
1.854 - visitForTest(node->condition(), &success, &join, &success);
1.855 - __ bind(&success);
1.856 - node->ifTrue()->accept(this);
1.857 - } else {
1.858 - Label success, next;
1.859 -
1.860 - visitForTest(node->condition(), &success, &next, &success);
1.861 - __ bind(&success);
1.862 - node->ifTrue()->accept(this);
1.863 - __ jump(&join);
1.864 - __ bind(&next);
1.865 - node->ifFalse()->accept(this);
1.866 - }
1.867 -
1.868 - __ bind(&join);
1.869 -}
1.870 -
1.871 -void
1.872 -BytecodeCompiler::visit(FunctionStatement *node)
1.873 -{
1.874 - if (node->fun()->isNative()) {
1.875 - assert(!moduleData_->natives->at(node->fun()->slot()));
1.876 -
1.877 - Local<Type> type(zone_, node->fun()->type());
1.878 - Local<String> name(zone_, node->fun()->name());
1.879 - Local<Native> native(zone_, Native::New(zone_, type, name));
1.880 - if (!native)
1.881 - return;
1.882 -
1.883 - moduleData_->natives->set(zone_, node->fun()->slot(), native);
1.884 - return;
1.885 - }
1.886 -
1.887 - // If the function has no body, then it's just a declaration.
1.888 - if (!node->body()) {
1.889 - assert(node->fun()->isForward() || node->fun()->isPublic());
1.890 - return;
1.891 - }
1.892 -
1.893 - BytecodeCompiler child(zone_, tree_, moduleData_);
1.894 - Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
1.895 - if (!fun)
1.896 - return;
1.897 -
1.898 - assert(!moduleData_->module->getFunction(node->fun()->slot()));
1.899 - moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
1.900 -}
1.901 -
1.902 -void
1.903 -BytecodeCompiler::visit(EnumStatement *node)
1.904 -{
1.905 - // :TODO: eventually, we'll export these.
1.906 -}
1.907 -
1.908 -Code *
1.909 -BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
1.910 -{
1.911 - // STOP doubles as RETURNVOID.
1.912 - __ stop();
1.913 -
1.914 - if (__ oom() || zone_->hasPendingException())
1.915 - return NULL;
1.916 -
1.917 - Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
1.918 - if (!bytes)
1.919 - return NULL;
1.920 - memcpy(bytes->raw(), __ buffer(), __ length());
1.921 -
1.922 - for (size_t i = 0; i < scope->maxContainedLocals(); i++)
1.923 - assert(locals_->at(i));
1.924 -
1.925 - Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
1.926 - if (!objects)
1.927 - return NULL;
1.928 -
1.929 - for (size_t i = 0; i < __ objects()->length(); i++)
1.930 - objects->set(zone_, i, *(__ objects()->at(i)));
1.931 -
1.932 - Local<ByteArray> safepoints(zone_);
1.933 -
1.934 - // If any stack slots hold gc pointers at potential failure points in the
1.935 - // bytecode, record them now. We do this by building a list of tuples;
1.936 - // each tuple contains the pc offset, and a bitset containing which stack
1.937 - // slots must be scanned by the gc.
1.938 - if (__ oopRecords()->length()) {
1.939 - size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
1.940 - size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
1.941 - safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
1.942 - if (!safepoints)
1.943 - return NULL;
1.944 -
1.945 - Address cursor = safepoints->raw();
1.946 - for (size_t i = 0; i < __ oopRecords()->length(); i++) {
1.947 - OopRecord *record = __ oopRecords()->at(i);
1.948 - assert(record->depth <= __ maxStackDepth());
1.949 -
1.950 - *reinterpret_cast<unsigned *>(cursor) = record->offset;
1.951 -
1.952 - unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
1.953 - for (unsigned i = 0; i < record->depth; i++)
1.954 - bits[i / 8] |= (1 << (i % 8));
1.955 -
1.956 - cursor += bytesPerSafepoint;
1.957 - }
1.958 -
1.959 - assert(cursor == safepoints->raw() + gcmapSize);
1.960 - }
1.961 -
1.962 - Local<ByteArray> sourcemap(zone_);
1.963 - if (__ sourcemapLength()) {
1.964 - sourcemap = ByteArray::New(zone_, __ sourcemapLength(), Heap::Tenure_Old);
1.965 - if (!sourcemap)
1.966 - return NULL;
1.967 -
1.968 - memcpy(sourcemap->raw(), __ sourcemap(), __ sourcemapLength());
1.969 - }
1.970 -
1.971 - Local<Code> code(zone_);
1.972 -
1.973 - code = Code::New(zone_,
1.974 - bytes,
1.975 - locals_,
1.976 - objects,
1.977 - __ maxStackDepth(),
1.978 - moduleData_->module,
1.979 - safepoints,
1.980 - sourcemap,
1.981 - lineno);
1.982 - return code;
1.983 -}
1.984 -
1.985 -Function *
1.986 -BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
1.987 -{
1.988 - // Note: No need to record a life slot here, since it's part of the Frame.
1.989 - AutoEnterScope functionScope(this, node->scope());
1.990 -
1.991 - // Set the initial line, because line mappings are deltas.
1.992 - __ setFirstLine(node->pos().line);
1.993 - locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
1.994 -
1.995 - node->body()->accept(this);
1.996 -
1.997 - unsigned nargs = node->scope()->numArguments();
1.998 - Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
1.999 - if (!args)
1.1000 - return NULL;
1.1001 -
1.1002 - for (size_t i = 0; i < node->scope()->numArguments(); i++)
1.1003 - args->set(zone_, i, node->scope()->getArgument(i)->type());
1.1004 -
1.1005 -
1.1006 - Local<Code> code(zone_, compileCode(node->scope(), node->pos().line));
1.1007 - if (!code)
1.1008 - return NULL;
1.1009 -
1.1010 - Local<Type> type(zone_, node->fun()->type());
1.1011 - Local<String> name(zone_, node->fun()->name());
1.1012 - Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
1.1013 - if (!fun)
1.1014 - return NULL;
1.1015 -
1.1016 - // If this function had a forward, export it as a named public.
1.1017 - if (node->fun()->isPublic()) {
1.1018 - assert(node->fun()->isPublic());
1.1019 - ScopedRoot<Function> root(fun);
1.1020 - if (!root)
1.1021 - return NULL;
1.1022 - if (!moduleData_->publics.append(root))
1.1023 - return NULL;
1.1024 - }
1.1025 -
1.1026 - Disassemble(code, stdout);
1.1027 -
1.1028 - return fun;
1.1029 -}
1.1030 -
1.1031 -Module *
1.1032 -BytecodeCompiler::compile()
1.1033 -{
1.1034 - AutoEnterScope scope(this, tree_->scope());
1.1035 -
1.1036 - ModuleData moduleData;
1.1037 -
1.1038 - moduleData_ = &moduleData;
1.1039 - moduleData_->module = Module::New(zone_, tree_->scope()->numFunctions());
1.1040 -
1.1041 - if (!moduleData_)
1.1042 - return NULL;
1.1043 -
1.1044 - moduleData_->natives = FixedArray::New(zone_, tree_->scope()->numNatives(), Heap::Tenure_Old);
1.1045 - if (!moduleData_->natives)
1.1046 - return NULL;
1.1047 -
1.1048 - for (size_t i = 0; i < tree_->statements()->length(); i++) {
1.1049 - Statement *statement = tree_->statements()->at(i);
1.1050 - statement->accept(this);
1.1051 - }
1.1052 -
1.1053 - if (zone_->hasPendingException())
1.1054 - return NULL;
1.1055 -
1.1056 -#ifndef NDEBUG
1.1057 - for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
1.1058 - assert(moduleData_->module->getFunction(i));
1.1059 - for (size_t i = 0; i < tree_->scope()->numNatives(); i++)
1.1060 - assert(moduleData_->natives->at(i));
1.1061 -#endif
1.1062 -
1.1063 - if (moduleData_->publics.length()) {
1.1064 - Local<Function> fun(zone_);
1.1065 - Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
1.1066 - Heap::Tenure_Old));
1.1067 - if (!list)
1.1068 - return NULL;
1.1069 -
1.1070 - for (size_t i = 0; i < moduleData_->publics.length(); i++)
1.1071 - list->set(zone_, i, moduleData_->publics[i]);
1.1072 -
1.1073 - moduleData_->module->setPublics(list);
1.1074 - }
1.1075 -
1.1076 - moduleData_->module->setNatives(moduleData_->natives);
1.1077 -
1.1078 - if (scope_->numEnvironmentVars()) {
1.1079 - Local<EnvironmentMap> globalMap(zone_, scope_->createEnvironmentMap(zone_));
1.1080 - if (!globalMap)
1.1081 - return NULL;
1.1082 -
1.1083 - Local<Environment> environment(zone_, Environment::New(zone_, globalMap));
1.1084 - if (!environment)
1.1085 - return NULL;
1.1086 -
1.1087 - moduleData_->module->setEnvironment(environment);
1.1088 - }
1.1089 -
1.1090 - Local<Code> code(zone_, compileCode(tree_->scope(), 1));
1.1091 - if (!code)
1.1092 - return NULL;
1.1093 -
1.1094 - Disassemble(code, stdout);
1.1095 -
1.1096 - moduleData_->module->setCode(code);
1.1097 -
1.1098 - return moduleData_->module;
1.1099 -}