Handle-ize BytecodeEmitter.
1 /* vim: set ts=4 sw=4 tw=99 et:
3 * Copyright (C) 2012 David Anderson
5 * This file is part of JITCraft.
7 * JITCraft is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License as published by the Free
9 * Software Foundation, either version 3 of the License, or (at your option)
12 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with
17 * JITCraft. If not, see http://www.gnu.org/licenses/.
19 #include "BytecodeCompiler.h"
29 typedef BytecodeEmitter::Label Label;
33 BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, Module *module)
43 static inline TokenKind
44 ToCompare(Expression *expr)
46 if (expr->isBinaryExpression()) {
47 BinaryExpression *b = expr->toBinaryExpression();
48 if (b->token() >= TOK_EQUALS && b->token() <= TOK_GE)
55 CompareTokenToJump(TokenKind kind)
69 assert(kind == TOK_LE);
75 TokenToOpcode(TokenKind kind)
97 assert(kind == TOK_BITXOR);
103 BytecodeCompiler::recordLifoSlot(Scope *scope)
108 if (Variable *var = scope->lifoSlot()) {
109 locals_->set(zone_, var->slot(), var->type());
110 __ savelifo(var->slot());
115 BytecodeCompiler::unwindTo(Scope *scope)
117 // Note: we only need to unwind to the outermost scope's LIFO slot.
118 Variable *var = NULL;
119 for (Scope *current = scope_; current != scope; current = current->enclosing()) {
120 if (Variable *slot = current->lifoSlot())
125 __ unwindlifo(var->slot());
129 BytecodeCompiler::visit(NameProxy *name)
131 switch (name->binding()->kind()) {
132 case BoundName::VARIABLE:
134 Variable *var = name->binding()->toVariable();
136 if (var->location() == Variable::STACK) {
137 __ getlocal(var->slot());
138 assert(!name->type()->isReference());
140 assert(var->location() == Variable::PARAMETER);
141 __ getarg(var->slot());
143 // If this argument is actually a reference, dereference it now.
144 if (var->type()->isReference())
145 __ getref(var->type()->contained()->primitive());
152 NamedConstant *constant = name->binding()->toNamedConstant();
153 __ int_(constant->value().toInt());
160 BytecodeCompiler::visit(ExpressionStatement *node)
162 // Expressions leave their value on the top of the stack, so we make sure
163 // to balance the stack if they're used as a statement.
164 node->expression()->accept(this);
169 BytecodeCompiler::visit(Assignment *node)
171 // The first step is three sub-steps:
173 // (1) Bind the left-hand side.
174 // -- If a cumulative operation (+=, etc):
175 // (2) Save a copy of the binding on the stack.
176 // (3) Dereference the binding to get a value.
178 if (node->lvalue()->isNameProxy()) {
179 NameProxy *proxy = node->lvalue()->toNameProxy();
180 Variable *var = proxy->binding()->toVariable();
183 if (var->type()->isReference() || var->type()->isArray())
186 // Get the value if needed.
187 if (node->token() != TOK_ASSIGN) {
188 // += etc is not allowed on arrays.
189 assert(!var->type()->isArray());
191 if (var->type()->isReference()) {
193 __ getref(var->type()->contained()->primitive());
199 IndexExpression *index = node->lvalue()->toIndexExpression();
201 // Note: Eventually, watch out for a whole here. An expression like:
203 // (a[4] = (5, a = []))
205 // Could shrink array, so we need to either bind a[i] to a Reference,
206 // or keep the bounds check near the set. This is just a semantic
208 index->left()->accept(this);
209 index->right()->accept(this);
211 if (node->token() != TOK_ASSIGN) {
214 if (node->type()->isArray())
217 __ getarray(node->type()->primitive());
221 if (node->token() == TOK_ASSIGN) {
222 node->expression()->accept(this);
224 visitForALU(node->type(), node->expression());
226 TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
227 __ binary(TokenToOpcode(alu));
231 if (node->expression()->type()->isArray()) {
232 // Unlike references, which can only be computed from a NamePRoxy,
233 // arrays can be computed from multiple lvalue types.
235 } else if (node->lvalue()->isNameProxy()) {
236 NameProxy *proxy = node->lvalue()->toNameProxy();
237 Variable *var = proxy->binding()->toVariable();
239 if (var->type()->isReference())
240 __ setref(var->type()->contained()->primitive());
244 IndexExpression *index = node->lvalue()->toIndexExpression();
245 // :TODO: get rid of the BOUNDS instruction, embed it in g/setarray*?
246 // We can't emit it here because the stack is slightly out of position.
248 __ setarray(index->left()->type()->contained()->primitive());
253 BytecodeCompiler::visit(IncDecExpression *node)
255 // In the postfix case, the logic looks like:
257 // (2) Dup -> REF REF
258 // (3) Fetch -> REF VAL
259 // (4) Swap -> VAL REF
260 // (5) Pick -> VAL REF VAL
261 // (6) Add -> VAL REF VAL+1
262 // (7) Store -> VAL VAL+1
265 // In the prefix case, the logic looks like:
267 // (2) Dup -> REF REF
268 // (3) Fetch -> REF VAL
271 // (6) Add -> REF VAL+1
272 // (7) Store -> VAL+1
275 // This is squirrely enough such that we don't bother sharing too much
278 // Note: We simulate a "Pick" operation with a dup2+pop.
280 // This is steps (1) to (5).
281 Expression *expr = node->expression();
282 if (expr->isNameProxy()) {
283 NameProxy *proxy = expr->toNameProxy();
284 Variable *var = proxy->binding()->toVariable();
287 if (var->type()->isReference() || var->type()->isArray())
291 if (var->type()->isReference()) {
293 __ getref(node->type()->primitive());
294 if (node->postfix()) {
299 assert(!var->type()->isArray());
305 IndexExpression *index = expr->toIndexExpression();
306 index->left()->accept(this);
307 index->right()->accept(this);
309 assert(!node->type()->isArray());
312 __ getarray(node->type()->primitive());
314 if (node->postfix()) {
315 // The stack looks like this now:
318 // So we must use a PICK operation to rotate the stack into position.
319 __ roll3(); // INDEX VALUE ARRAY
320 __ roll3(); // VALUE ARRAY INDEX
321 __ pick3(); // VALUE ARRAY INDEX VALUE
326 if (node->type()->isFloat()) {
329 assert(node->type()->isInt32());
333 if (node->token() == TOK_INCREMENT)
339 if (expr->isNameProxy()) {
340 NameProxy *proxy = expr->toNameProxy();
341 Variable *var = proxy->binding()->toVariable();
343 if (var->type()->isReference())
344 __ setref(node->type()->primitive());
348 __ setarray(node->type()->primitive());
357 BytecodeCompiler::visitForALU(Type *needed, Expression *node)
360 if (needed->isFloat() && !node->type()->isFloat())
363 assert(needed->primitive() == node->type()->primitive());
367 BytecodeCompiler::visit(BinaryExpression *node)
369 visitForALU(node->type(), node->left());
370 visitForALU(node->type(), node->right());
372 Opcode op = TokenToOpcode(node->token());
373 if (node->type()->isFloat())
374 op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
379 BytecodeCompiler::visit(IndexExpression *node)
381 node->left()->accept(this);
382 node->right()->accept(this);
385 if (node->type()->isArray())
388 __ getarray(node->type()->primitive());
392 BytecodeCompiler::visit(ReturnStatement *node)
394 if (node->expression())
395 node->expression()->accept(this);
403 BytecodeCompiler::visitForTest(Expression *expression, Label *label, bool onTrue)
405 TokenKind token = ToCompare(expression);
406 if (token == TOK_EOF) {
407 expression->accept(this);
415 Opcode op = CompareTokenToJump(token);
419 assert(expression->isBinaryExpression());
420 BinaryExpression *binary = expression->toBinaryExpression();
421 binary->left()->accept(this);
422 binary->right()->accept(this);
427 BytecodeCompiler::visit(ForStatement *node)
429 AutoEnterScope forScope(this, node->scope());
431 recordLifoSlot(node->scope());
434 LoopScope loop(scope_, &join, &update, &loop_);
436 if (node->initialization())
437 node->initialization()->accept(this);
440 if (node->condition())
444 node->body()->accept(this);
448 node->update()->accept(this);
450 if (node->condition()) {
452 visitForTest(node->condition(), &header, true);
460 unwindTo(node->scope()->enclosing());
461 assert(__ stackDepth() == 0);
465 BytecodeCompiler::visit(WhileStatement *node)
471 LoopScope loop(scope_, &join, &header, &loop_);
473 if (node->token() == TOK_WHILE) {
474 visitForTest(node->condition(), &join, false);
475 node->body()->accept(this);
478 node->body()->accept(this);
479 visitForTest(node->condition(), &header, true);
486 BytecodeCompiler::visit(BreakStatement *node)
488 unwindTo(loop_->scope());
489 __ jump(loop_->break_());
493 BytecodeCompiler::visit(ContinueStatement *node)
495 unwindTo(loop_->scope());
496 __ jump(loop_->continue_());
500 BytecodeCompiler::visit(BlockStatement *node)
502 AutoEnterScope blockScope(this, node->scope());
504 recordLifoSlot(node->scope());
506 for (size_t i = 0; i < node->statements()->length(); i++) {
507 Statement *statement = node->statements()->at(i);
508 statement->accept(this);
509 assert(__ stackDepth() == 0);
512 // We don't bother emitting an "unwind" instruction for function scopes,
513 // since this is taken care of by the calling convention.
514 if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
515 unwindTo(node->scope()->enclosing());
519 BytecodeCompiler::visit(IntegerLiteral *node)
521 __ int_(node->value());
525 BytecodeCompiler::visit(FloatLiteral *node)
527 __ float_((float)node->value());
530 static inline ArrayMap *
531 BuildArrayMap(Zone *zone, Handle<Type> type)
533 Local<ArrayMap> contained(zone);
534 if (type->levels() > 1) {
535 Local<Type> containedType(zone, type->contained());
536 contained = BuildArrayMap(zone, containedType);
541 return ArrayMap::New(zone, type, contained);
545 BytecodeCompiler::visit(StringLiteral *node)
547 Local<Type> type(zone_, node->type());
548 Local<ArrayMap> map(zone_, BuildArrayMap(zone_, type));
552 Local<Array> array(zone_, Array::New(zone_, map, node->string()->length(), Heap::Tenure_Old));
556 assert(array->nelements() >= node->string()->length());
557 memcpy(array->chars(), node->string()->raw(), node->string()->length() * sizeof(char));
563 BytecodeCompiler::visit(VariableDeclaration *node)
565 Variable *var = node->variable();
566 assert(var->location() == Variable::STACK);
568 Local<Type> type(zone_, var->type());
569 if (type->isArray()) {
570 Local<ArrayMap> map(zone_, 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 Local<Type> funType(zone_, node->callee()->type());
596 for (size_t i = 0; i < node->arguments()->size(); i++) {
597 Expression *arg = node->arguments()->at(i);
599 Local<Type> given(zone_, arg->type());
600 Local<Type> actual(zone_, Type::cast(funType->parameters()->at(i)));
601 if (actual->isReference()) {
602 if (given->isReference()) {
603 // The input type is already a reference, so we're just passing
604 // it on to the callee.
606 } else if (arg->isNameProxy()) {
607 // :TODO: test with functions and globals
608 // Compute a reference to the name.
609 Variable *var = arg->toNameProxy()->binding()->toVariable();
611 } else if (arg->isIndexExpression()) {
612 IndexExpression *expr = arg->toIndexExpression();
613 expr->left()->accept(this);
614 expr->right()->accept(this);
618 // We don't know how to, or can't, build a direct reference to
619 // this type. Make an indirect one, by taking the top of the
620 // stack and boxing it up.
629 __ callglobal(node->arguments()->size(), 0);
633 BytecodeCompiler::visit(IfStatement *node)
635 if (!node->ifFalse()) {
637 visitForTest(node->condition(), &fail, false);
638 node->ifTrue()->accept(this);
642 visitForTest(node->condition(), &fail, false);
643 node->ifTrue()->accept(this);
646 node->ifFalse()->accept(this);
652 BytecodeCompiler::visit(FunctionStatement *node)
654 BytecodeCompiler child(zone_, tree_, module_);
655 Local<Function> fun(zone_, child.compileFunction(module_, node));
659 assert(!module_->getFunction(node->fun()->slot()));
660 module_->setFunction(zone_, node->fun()->slot(), fun);
664 BytecodeCompiler::visit(EnumStatement *node)
666 // :TODO: eventually, we'll export these.
670 BytecodeCompiler::compileFunction(Module *module, FunctionStatement *node)
672 // Note: No need to record a life slot here, since it's part of the Frame.
673 AutoEnterScope functionScope(this, node->scope());
675 locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
677 node->body()->accept(this);
684 Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
687 memcpy(bytes->raw(), __ buffer(), __ length());
689 unsigned nargs = node->scope()->numArguments();
690 Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
694 for (size_t i = 0; i < node->scope()->numArguments(); i++)
695 args->set(zone_, i, node->scope()->getArgument(i)->type());
697 for (size_t i = 0; i < node->scope()->maxContainedLocals(); i++)
698 assert(locals_->at(i));
700 Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->size(), Heap::Tenure_Old));
704 for (size_t i = 0; i < __ objects()->size(); i++)
705 objects->set(zone_, i, *(__ objects()->at(i)));
707 Local<Code> code(zone_, Code::New(zone_, bytes, locals_, objects, __ maxStackDepth(), module_));
711 Local<Function> fun(zone_, Function::New(zone_, module_, code, node->fun()->type(), node->pos()));
719 BytecodeCompiler::compile()
721 module_ = Module::New(zone_, tree_->scope()->numFunctions());
725 for (size_t i = 0; i < tree_->statements()->length(); i++) {
726 Statement *statement = tree_->statements()->at(i);
727 statement->accept(this);
731 for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
732 assert(module_->getFunction(i));