Implement ++ and -- operators.
2 * Copyright (C) 2012 David Anderson
4 * This file is part of JITCraft.
6 * JITCraft is free software: you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License as published by the Free
8 * Software Foundation, either version 3 of the License, or (at your option)
11 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * JITCraft. If not, see http://www.gnu.org/licenses/.
18 #include "BytecodeCompiler.h"
28 typedef BytecodeEmitter::Label Label;
32 BytecodeCompiler::BytecodeCompiler(ParseTree *tree, Module *module)
40 static inline TokenKind
41 ToCompare(Expression *expr)
43 if (expr->isBinaryExpression()) {
44 BinaryExpression *b = expr->toBinaryExpression();
45 if (b->token() >= TOK_EQUALS && b->token() <= TOK_GE)
52 CompareTokenToJump(TokenKind kind)
73 TokenToOpcode(TokenKind kind)
102 BytecodeCompiler::recordLifoSlot(Scope *scope)
107 if (Variable *var = scope->lifoSlot()) {
108 locals_->set(ZONE(), var->slot(), var->type());
109 __ savelifo(var->slot());
114 BytecodeCompiler::unwindTo(Scope *scope)
116 // Note: we only need to unwind to the outermost scope's LIFO slot.
117 Variable *var = NULL;
118 for (Scope *current = scope_; current != scope; current = current->enclosing()) {
119 if (Variable *slot = current->lifoSlot())
124 __ unwindlifo(var->slot());
128 BytecodeCompiler::visit(NameProxy *name)
130 switch (name->binding()->kind()) {
131 case BoundName::VARIABLE:
133 Variable *var = name->binding()->toVariable();
135 if (var->location() == Variable::STACK) {
136 __ getlocal(var->slot());
137 assert(!name->type()->isReference());
139 assert(var->location() == Variable::PARAMETER);
140 __ getarg(var->slot());
142 // If this argument is actually a reference, dereference it now.
143 if (var->type()->isReference())
144 __ getref(var->type()->contained()->primitive());
151 NamedConstant *constant = name->binding()->toNamedConstant();
152 __ int_(constant->value().toInt());
159 BytecodeCompiler::visit(ExpressionStatement *node)
161 // Expressions leave their value on the top of the stack, so we make sure
162 // to balance the stack if they're used as a statement.
163 node->expression()->accept(this);
168 BytecodeCompiler::visit(Assignment *node)
170 // The first step is three sub-steps:
172 // (1) Bind the left-hand side.
173 // -- If a cumulative operation (+=, etc):
174 // (2) Save a copy of the binding on the stack.
175 // (3) Dereference the binding to get a value.
177 if (node->lvalue()->isNameProxy()) {
178 NameProxy *proxy = node->lvalue()->toNameProxy();
179 Variable *var = proxy->binding()->toVariable();
182 if (var->type()->isReference() || var->type()->isArray())
185 // Get the value if needed.
186 if (node->token() != TOK_ASSIGN) {
187 // += etc is not allowed on arrays.
188 assert(!var->type()->isArray());
190 if (var->type()->isReference()) {
192 __ getref(var->type()->contained()->primitive());
198 IndexExpression *index = node->lvalue()->toIndexExpression();
200 // Note: Eventually, watch out for a whole here. An expression like:
202 // (a[4] = (5, a = []))
204 // Could shrink array, so we need to either bind a[i] to a Reference,
205 // or keep the bounds check near the set. This is just a semantic
207 index->left()->accept(this);
208 index->right()->accept(this);
210 if (node->token() != TOK_ASSIGN) {
213 if (node->type()->isArray())
216 __ getarray(node->type()->primitive());
220 if (node->token() == TOK_ASSIGN) {
221 node->expression()->accept(this);
223 visitForALU(node->type(), node->expression());
225 TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
226 __ binary(TokenToOpcode(alu));
230 if (node->expression()->type()->isArray()) {
231 // Unlike references, which can only be computed from a NamePRoxy,
232 // arrays can be computed from multiple lvalue types.
234 } else if (node->lvalue()->isNameProxy()) {
235 NameProxy *proxy = node->lvalue()->toNameProxy();
236 Variable *var = proxy->binding()->toVariable();
238 if (var->type()->isReference())
239 __ setref(var->type()->contained()->primitive());
243 IndexExpression *index = node->lvalue()->toIndexExpression();
244 // :TODO: get rid of the BOUNDS instruction, embed it in g/setarray*?
245 // We can't emit it here because the stack is slightly out of position.
247 __ setarray(index->left()->type()->contained()->primitive());
252 BytecodeCompiler::visit(IncDecExpression *node)
254 // In the postfix case, the logic looks like:
256 // (2) Dup -> REF REF
257 // (3) Fetch -> REF VAL
258 // (4) Swap -> VAL REF
259 // (5) Pick -> VAL REF VAL
260 // (6) Add -> VAL REF VAL+1
261 // (7) Store -> VAL VAL+1
264 // In the prefix case, the logic looks like:
266 // (2) Dup -> REF REF
267 // (3) Fetch -> REF VAL
270 // (6) Add -> REF VAL+1
271 // (7) Store -> VAL+1
274 // This is squirrely enough such that we don't bother sharing too much
277 // Note: We simulate a "Pick" operation with a dup2+pop.
279 // This is steps (1) to (5).
280 Expression *expr = node->expression();
281 if (expr->isNameProxy()) {
282 NameProxy *proxy = expr->toNameProxy();
283 Variable *var = proxy->binding()->toVariable();
286 if (var->type()->isReference() || var->type()->isArray())
290 if (var->type()->isReference()) {
292 __ getref(node->type()->primitive());
293 if (node->postfix()) {
298 assert(!var->type()->isArray());
304 IndexExpression *index = expr->toIndexExpression();
305 index->left()->accept(this);
306 index->right()->accept(this);
308 assert(!node->type()->isArray());
311 __ getarray(node->type()->primitive());
313 if (node->postfix()) {
314 // The stack looks like this now:
317 // So we must use a PICK operation to rotate the stack into position.
318 __ roll3(); // INDEX VALUE ARRAY
319 __ roll3(); // VALUE ARRAY INDEX
320 __ pick3(); // VALUE ARRAY INDEX VALUE
325 if (node->type()->isFloat()) {
328 assert(node->type()->isInt32());
332 if (node->token() == TOK_INCREMENT)
338 if (expr->isNameProxy()) {
339 NameProxy *proxy = expr->toNameProxy();
340 Variable *var = proxy->binding()->toVariable();
342 if (var->type()->isReference())
343 __ setref(node->type()->primitive());
347 __ setarray(node->type()->primitive());
356 BytecodeCompiler::visitForALU(Type *needed, Expression *node)
359 if (needed->isFloat() && !node->type()->isFloat())
362 assert(needed->primitive() == node->type()->primitive());
366 BytecodeCompiler::visit(BinaryExpression *node)
368 visitForALU(node->type(), node->left());
369 visitForALU(node->type(), node->right());
371 Opcode op = TokenToOpcode(node->token());
372 if (node->type()->isFloat())
373 op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
378 BytecodeCompiler::visit(IndexExpression *node)
380 node->left()->accept(this);
381 node->right()->accept(this);
384 if (node->type()->isArray())
387 __ getarray(node->type()->primitive());
391 BytecodeCompiler::visit(ReturnStatement *node)
393 if (node->expression())
394 node->expression()->accept(this);
402 BytecodeCompiler::visitForTest(Expression *expression, Label *label, bool onTrue)
404 TokenKind token = ToCompare(expression);
405 if (token == TOK_EOF) {
406 expression->accept(this);
414 Opcode op = CompareTokenToJump(token);
418 assert(expression->isBinaryExpression());
419 BinaryExpression *binary = expression->toBinaryExpression();
420 binary->left()->accept(this);
421 binary->right()->accept(this);
426 BytecodeCompiler::visit(ForStatement *node)
428 AutoEnterScope forScope(this, node->scope());
430 recordLifoSlot(node->scope());
433 LoopScope loop(scope_, &join, &update, &loop_);
435 if (node->initialization())
436 node->initialization()->accept(this);
439 if (node->condition())
443 node->body()->accept(this);
447 node->update()->accept(this);
449 if (node->condition()) {
451 visitForTest(node->condition(), &header, true);
459 unwindTo(node->scope()->enclosing());
460 assert(__ stackDepth() == 0);
464 BytecodeCompiler::visit(WhileStatement *node)
470 LoopScope loop(scope_, &join, &header, &loop_);
472 if (node->token() == TOK_WHILE) {
473 visitForTest(node->condition(), &join, false);
474 node->body()->accept(this);
477 node->body()->accept(this);
478 visitForTest(node->condition(), &header, true);
485 BytecodeCompiler::visit(BreakStatement *node)
487 unwindTo(loop_->scope());
488 __ jump(loop_->break_());
492 BytecodeCompiler::visit(ContinueStatement *node)
494 unwindTo(loop_->scope());
495 __ jump(loop_->continue_());
499 BytecodeCompiler::visit(BlockStatement *node)
501 AutoEnterScope blockScope(this, node->scope());
503 recordLifoSlot(node->scope());
505 for (size_t i = 0; i < node->statements()->length(); i++) {
506 Statement *statement = node->statements()->at(i);
507 statement->accept(this);
508 assert(__ stackDepth() == 0);
511 // We don't bother emitting an "unwind" instruction for function scopes,
512 // since this is taken care of by the calling convention.
513 if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
514 unwindTo(node->scope()->enclosing());
518 BytecodeCompiler::visit(IntegerLiteral *node)
520 __ int_(node->value());
524 BytecodeCompiler::visit(FloatLiteral *node)
526 __ float_((float)node->value());
529 static inline ArrayMap *
530 BuildArrayMap(Zone *zone, Type *type)
533 ArrayMap *contained = NULL;
534 if (type->levels() > 1) {
535 contained = BuildArrayMap(zone, type->contained());
540 return ArrayMap::New(zone, type, contained);
544 BytecodeCompiler::visit(StringLiteral *node)
547 ArrayMap *map = BuildArrayMap(ZONE(), node->type());
551 Array *array = Array::New(ZONE(), map, node->string()->length(), Heap::Tenure_Old);
555 assert(array->nelements() >= node->string()->length());
556 memcpy(array->chars(), node->string()->raw(), node->string()->length() * sizeof(char));
562 BytecodeCompiler::visit(VariableDeclaration *node)
564 Variable *var = node->variable();
565 assert(var->location() == Variable::STACK);
567 Type *type = var->type();
568 if (type->isArray()) {
570 ArrayMap *map = BuildArrayMap(ZONE(), type);
571 __ newarray_lifo(map);
573 if (node->initialization()) {
574 node->initialization()->accept(this);
578 if (node->initialization()) {
579 node->initialization()->accept(this);
581 if (!node->postDimensions())
585 __ setlocal(var->slot());
588 locals_->set(ZONE(), var->slot(), var->type());
592 BytecodeCompiler::visit(CallExpression *node)
594 NameProxy *fun = node->callee()->toNameProxy();
597 Type *funType = node->callee()->type();
599 for (size_t i = 0; i < node->arguments()->size(); i++) {
600 Expression *arg = node->arguments()->at(i);
602 Type *given = arg->type();
603 Type *actual = Type::cast(funType->parameters()->at(i));
604 if (actual->isReference()) {
605 if (given->isReference()) {
606 // The input type is already a reference, so we're just passing
607 // it on to the callee.
609 } else if (arg->isNameProxy()) {
610 // :TODO: test with functions and globals
611 // Compute a reference to the name.
612 Variable *var = arg->toNameProxy()->binding()->toVariable();
614 } else if (arg->isIndexExpression()) {
615 IndexExpression *expr = arg->toIndexExpression();
616 expr->left()->accept(this);
617 expr->right()->accept(this);
621 // We don't know how to, or can't, build a direct reference to
622 // this type. Make an indirect one, by taking the top of the
623 // stack and boxing it up.
632 __ callglobal(node->arguments()->size(), 0);
636 BytecodeCompiler::visit(IfStatement *node)
638 if (!node->ifFalse()) {
640 visitForTest(node->condition(), &fail, false);
641 node->ifTrue()->accept(this);
645 visitForTest(node->condition(), &fail, false);
646 node->ifTrue()->accept(this);
649 node->ifFalse()->accept(this);
655 BytecodeCompiler::visit(FunctionStatement *node)
657 BytecodeCompiler child(tree_, module_);
658 Code *code = child.compileFunction(module_, node);
660 assert(!module_->getFunction(node->fun()->slot()));
661 module_->setFunction(ZONE(), node->fun()->slot(), code);
665 BytecodeCompiler::visit(EnumStatement *node)
667 // :TODO: eventually, we'll export these.
671 BytecodeCompiler::compileFunction(Module *module, FunctionStatement *node)
673 // Note: No need to record a life slot here, since it's part of the Frame.
674 AutoEnterScope functionScope(this, node->scope());
677 locals_ = FixedArray::New(ZONE(), node->scope()->maxContainedLocals(), Heap::Tenure_Old);
679 node->body()->accept(this);
686 ByteArray *bytes = ByteArray::New(ZONE(), __ length() * sizeof(bytecode), Heap::Tenure_Old);
689 memcpy(bytes->raw(), __ buffer(), __ length());
691 unsigned nargs = node->scope()->numArguments();
692 FixedArray *args = FixedArray::New(ZONE(), nargs, Heap::Tenure_Old);
696 for (size_t i = 0; i < node->scope()->numArguments(); i++)
697 args->set(ZONE(), i, node->scope()->getArgument(i)->type());
699 for (size_t i = 0; i < node->scope()->maxContainedLocals(); i++)
700 assert(locals_->at(i));
702 FixedArray *objects = FixedArray::New(ZONE(), __ objects()->size(), Heap::Tenure_Old);
706 for (size_t i = 0; i < __ objects()->size(); i++)
707 objects->set(ZONE(), i, __ objects()->at(i));
709 Code *code = Code::New(ZONE(), bytes, locals_, args, objects, __ maxStackDepth(), module_);
714 BytecodeCompiler::compile()
717 module_ = Module::New(ZONE(), tree_->scope()->numFunctions());
721 for (size_t i = 0; i < tree_->statements()->length(); i++) {
722 Statement *statement = tree_->statements()->at(i);
723 statement->accept(this);
727 for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
728 assert(module_->getFunction(i));