1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/jitcraft/BytecodeCompiler.cpp Mon Jun 25 02:57:28 2012 -0700
1.3 @@ -0,0 +1,365 @@
1.4 +/*
1.5 + * Copyright (C) 2012 David Anderson
1.6 + *
1.7 + * This file is part of JITCraft.
1.8 + *
1.9 + * JITCraft is free software: you can redistribute it and/or modify it under
1.10 + * the terms of the GNU General Public License as published by the Free
1.11 + * Software Foundation, either version 3 of the License, or (at your option)
1.12 + * any later version.
1.13 + *
1.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
1.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
1.17 + *
1.18 + * You should have received a copy of the GNU General Public License along with
1.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
1.20 + */
1.21 +#include "BytecodeCompiler.h"
1.22 +#include "Scopes.h"
1.23 +#include "Modules.h"
1.24 +#include "Types.h"
1.25 +
1.26 +using namespace jc;
1.27 +
1.28 +typedef BytecodeEmitter::Label Label;
1.29 +
1.30 +#define __ emitter_.
1.31 +
1.32 +BytecodeCompiler::BytecodeCompiler(ParseTree *tree)
1.33 + : tree_(tree)
1.34 +{
1.35 +}
1.36 +
1.37 +static inline TokenKind
1.38 +ToCompare(Expression *expr)
1.39 +{
1.40 + if (expr->isBinaryExpression()) {
1.41 + BinaryExpression *b = expr->toBinaryExpression();
1.42 + if (b->token() >= TOK_EQUALS && b->token() <= TOK_GE)
1.43 + return b->token();
1.44 + }
1.45 + return TOK_EOF;
1.46 +}
1.47 +
1.48 +static inline Opcode
1.49 +CompareTokenToJump(TokenKind kind)
1.50 +{
1.51 + switch (kind) {
1.52 + case TOK_EQUALS:
1.53 + return OP_JEQ;
1.54 + case TOK_NOTEQUALS:
1.55 + return OP_JNE;
1.56 + case TOK_GT:
1.57 + return OP_JG;
1.58 + case TOK_GE:
1.59 + return OP_JGE;
1.60 + case TOK_LT:
1.61 + return OP_JL;
1.62 + case TOK_LE:
1.63 + return OP_JLE;
1.64 + }
1.65 + assert(false);
1.66 + return OP_NOP;
1.67 +}
1.68 +
1.69 +static inline Opcode
1.70 +TokenToOpcode(TokenKind kind)
1.71 +{
1.72 + switch (kind) {
1.73 + case TOK_PLUS:
1.74 + return OP_ADD;
1.75 + case TOK_MINUS:
1.76 + return OP_SUB;
1.77 + case TOK_STAR:
1.78 + return OP_MUL;
1.79 + case TOK_SLASH:
1.80 + return OP_DIV;
1.81 + }
1.82 + assert(false);
1.83 + return OP_NOP;
1.84 +}
1.85 +
1.86 +void
1.87 +BytecodeCompiler::visit(NameProxy *name)
1.88 +{
1.89 + Variable *var = name->binding()->toVariable();
1.90 +
1.91 + if (var->location() == Variable::STACK) {
1.92 + __ getlocal(var->slot());
1.93 + } else {
1.94 + assert(var->location() == Variable::PARAMETER);
1.95 + __ getarg(var->slot());
1.96 + }
1.97 +}
1.98 +
1.99 +void
1.100 +BytecodeCompiler::visit(ExpressionStatement *node)
1.101 +{
1.102 + // Expressions leave their value on the top of the stack, so we make sure
1.103 + // to balance the stack if they're used as a statement.
1.104 + node->expression()->accept(this);
1.105 + __ pop();
1.106 +}
1.107 +
1.108 +void
1.109 +BytecodeCompiler::visit(Assignment *node)
1.110 +{
1.111 + if (node->lvalue()->isNameProxy()) {
1.112 + NameProxy *proxy = node->lvalue()->toNameProxy();
1.113 + Variable *var = proxy->binding()->toVariable();
1.114 +
1.115 + node->expression()->accept(this);
1.116 + if (var->location() == Variable::STACK) {
1.117 + __ setlocal(var->slot());
1.118 + } else {
1.119 + assert(var->location() == Variable::PARAMETER);
1.120 + __ setarg(var->slot());
1.121 + }
1.122 + } else if (node->lvalue()->isIndexExpression()) {
1.123 + IndexExpression *index = node->lvalue()->toIndexExpression();
1.124 +
1.125 + index->left()->accept(this);
1.126 + index->right()->accept(this);
1.127 + __ bounds_sta();
1.128 + node->expression()->accept(this);
1.129 + __ st_sta_i();
1.130 + }
1.131 +}
1.132 +
1.133 +void
1.134 +BytecodeCompiler::visit(BinaryExpression *node)
1.135 +{
1.136 + node->left()->accept(this);
1.137 + node->right()->accept(this);
1.138 +
1.139 + Opcode op = TokenToOpcode(node->token());
1.140 + __ binary(op);
1.141 +}
1.142 +
1.143 +void
1.144 +BytecodeCompiler::visit(IndexExpression *node)
1.145 +{
1.146 + node->left()->accept(this);
1.147 + node->right()->accept(this);
1.148 + __ bounds_sta();
1.149 +
1.150 + if (node->type()->isArray())
1.151 + __ ld_sta_p();
1.152 + else
1.153 + __ ld_sta_i();
1.154 +}
1.155 +
1.156 +void
1.157 +BytecodeCompiler::visit(ReturnStatement *node)
1.158 +{
1.159 + if (node->expression())
1.160 + node->expression()->accept(this);
1.161 + else
1.162 + __ int_(0);
1.163 +
1.164 + __ return_();
1.165 +}
1.166 +
1.167 +void
1.168 +BytecodeCompiler::visitForTest(Expression *expression, Label *label, bool onTrue)
1.169 +{
1.170 + TokenKind token = ToCompare(expression);
1.171 + if (token == TOK_EOF) {
1.172 + expression->accept(this);
1.173 + if (onTrue)
1.174 + __ j(OP_JT, label);
1.175 + else
1.176 + __ j(OP_JF, label);
1.177 + return;
1.178 + }
1.179 +
1.180 + Opcode op = CompareTokenToJump(token);
1.181 + if (!onTrue)
1.182 + op = Invert(op);
1.183 +
1.184 + assert(expression->isBinaryExpression());
1.185 + BinaryExpression *binary = expression->toBinaryExpression();
1.186 + binary->left()->accept(this);
1.187 + binary->right()->accept(this);
1.188 + __ j(op, label);
1.189 +}
1.190 +
1.191 +void
1.192 +BytecodeCompiler::visit(ForStatement *node)
1.193 +{
1.194 + if (node->declaration())
1.195 + node->declaration()->accept(this);
1.196 +
1.197 + Label header, test;
1.198 + if (node->condition())
1.199 + __ jump(&test);
1.200 +
1.201 + __ bind(&header);
1.202 + node->body()->accept(this);
1.203 +
1.204 + if (node->update())
1.205 + node->update()->accept(this);
1.206 +
1.207 + if (node->condition()) {
1.208 + __ bind(&test);
1.209 + visitForTest(node->condition(), &header, true);
1.210 + } else {
1.211 + __ jump(&header);
1.212 + }
1.213 +
1.214 + assert(__ stackDepth() == 0);
1.215 +}
1.216 +
1.217 +void
1.218 +BytecodeCompiler::visit(BlockStatement *node)
1.219 +{
1.220 + for (size_t i = 0; i < node->statements()->length(); i++) {
1.221 + Statement *statement = node->statements()->at(i);
1.222 + statement->accept(this);
1.223 + assert(__ stackDepth() == 0);
1.224 + }
1.225 +}
1.226 +
1.227 +void
1.228 +BytecodeCompiler::visit(IntegerLiteralExpression *node)
1.229 +{
1.230 + __ int_(node->value());
1.231 +}
1.232 +
1.233 +void
1.234 +BytecodeCompiler::visit(VariableDeclaration *node)
1.235 +{
1.236 + Variable *var = node->variable();
1.237 + assert(var->location() == Variable::STACK);
1.238 +
1.239 + Type *type = var->type();
1.240 + if (type->isArray()) {
1.241 + bool isConstant = true;
1.242 + for (Type *child = type; child->isArray(); child = child->contained()) {
1.243 + if (child->elements() == Type::UNKNOWN_SIZE) {
1.244 + isConstant = false;
1.245 + break;
1.246 + }
1.247 + }
1.248 +
1.249 + if (!isConstant) {
1.250 + for (size_t i = 0; i < node->postDimensions()->size(); i++) {
1.251 + Expression *expr = node->postDimensions()->at(i);
1.252 + expr->accept(this);
1.253 + }
1.254 + }
1.255 +
1.256 + __ stackarray(type);
1.257 + } else {
1.258 + if (node->initialization()) {
1.259 + node->initialization()->accept(this);
1.260 + } else {
1.261 + if (!node->postDimensions())
1.262 + __ int_(0);
1.263 + }
1.264 + }
1.265 + __ setlocal(var->slot());
1.266 + __ pop();
1.267 +
1.268 + locals_[var->slot()] = var->type();
1.269 +}
1.270 +
1.271 +void
1.272 +BytecodeCompiler::visit(CallExpression *node)
1.273 +{
1.274 + NameProxy *fun = node->callee()->toNameProxy();
1.275 +
1.276 + for (size_t i = 0; i < node->arguments()->size(); i++) {
1.277 + Expression *arg = node->arguments()->at(i);
1.278 + arg->accept(this);
1.279 + }
1.280 +
1.281 + __ callglobal(node->arguments()->size(), 0);
1.282 +}
1.283 +
1.284 +void
1.285 +BytecodeCompiler::visit(IfStatement *node)
1.286 +{
1.287 + if (!node->ifFalse()) {
1.288 + Label fail;
1.289 + visitForTest(node->condition(), &fail, false);
1.290 + node->ifTrue()->accept(this);
1.291 + __ bind(&fail);
1.292 + } else {
1.293 + Label fail, join;
1.294 + visitForTest(node->condition(), &fail, false);
1.295 + node->ifTrue()->accept(this);
1.296 + __ jump(&join);
1.297 + __ bind(&fail);
1.298 + node->ifFalse()->accept(this);
1.299 + __ bind(&join);
1.300 + }
1.301 +}
1.302 +
1.303 +void
1.304 +BytecodeCompiler::visit(FunctionStatement *node)
1.305 +{
1.306 + BytecodeCompiler child(tree_);
1.307 + Code *code = child.compileFunction(module_, node);
1.308 +
1.309 + assert(!module_->getFunction(node->fun()->slot()));
1.310 + module_->setFunction(node->fun()->slot(), code);
1.311 +}
1.312 +
1.313 +Code *
1.314 +BytecodeCompiler::compileFunction(Module *module, FunctionStatement *node)
1.315 +{
1.316 + locals_ = new Type *[node->scope()->maxContainedLocals()];
1.317 + memset(locals_, 0, sizeof(Type *) * node->scope()->maxContainedLocals());
1.318 +
1.319 + node->body()->accept(this);
1.320 +
1.321 + __ stop();
1.322 +
1.323 + if (__ oom())
1.324 + return false;
1.325 +
1.326 + bytecode *start = (bytecode *)malloc(__ length() * sizeof(bytecode));
1.327 + memcpy(start, __ buffer(), __ length());
1.328 +
1.329 + unsigned nargs = node->scope()->numArguments();
1.330 + Type **args = new Type *[nargs];
1.331 + for (size_t i = 0; i < node->scope()->numArguments(); i++)
1.332 + args[i] = node->scope()->getArgument(i)->type();
1.333 +
1.334 + for (size_t i = 0; i < node->scope()->maxContainedLocals(); i++)
1.335 + assert(locals_[i]);
1.336 +
1.337 + Code *code = new Code(module,
1.338 + start,
1.339 + __ length(),
1.340 + args,
1.341 + nargs,
1.342 + locals_,
1.343 + node->scope()->maxContainedLocals(),
1.344 + __ maxStackDepth());
1.345 +
1.346 + return code;
1.347 +}
1.348 +
1.349 +Module *
1.350 +BytecodeCompiler::compile()
1.351 +{
1.352 + Code **functions = new Code *[tree_->scope()->numFunctions()];
1.353 + memset(functions, 0, sizeof(Code *) * tree_->scope()->numFunctions());
1.354 +
1.355 + module_ = new Module(functions, tree_->scope()->numFunctions());
1.356 +
1.357 + for (size_t i = 0; i < tree_->statements()->length(); i++) {
1.358 + Statement *statement = tree_->statements()->at(i);
1.359 + statement->accept(this);
1.360 + }
1.361 +
1.362 +#ifndef NDEBUG
1.363 + for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
1.364 + assert(functions[i]);
1.365 +#endif
1.366 +
1.367 + return module_;
1.368 +}