1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/BytecodeCompiler.cpp Tue Jul 24 23:53:34 2012 -0700
1.3 @@ -0,0 +1,1096 @@
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 +}