|
dvander@0
|
1 |
/* |
|
dvander@0
|
2 |
* Copyright (C) 2012 David Anderson |
|
dvander@0
|
3 |
* |
|
dvander@0
|
4 |
* This file is part of JITCraft. |
|
dvander@0
|
5 |
* |
|
dvander@0
|
6 |
* JITCraft is free software: you can redistribute it and/or modify it under |
|
dvander@0
|
7 |
* the terms of the GNU General Public License as published by the Free |
|
dvander@0
|
8 |
* Software Foundation, either version 3 of the License, or (at your option) |
|
dvander@0
|
9 |
* any later version. |
|
dvander@0
|
10 |
* |
|
dvander@0
|
11 |
* Foobar is distributed in the hope that it will be useful, but WITHOUT ANY |
|
dvander@0
|
12 |
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|
dvander@0
|
13 |
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
|
dvander@0
|
14 |
* |
|
dvander@0
|
15 |
* You should have received a copy of the GNU General Public License along with |
|
dvander@0
|
16 |
* JITCraft. If not, see http://www.gnu.org/licenses/. |
|
dvander@0
|
17 |
*/ |
|
dvander@0
|
18 |
#include "BytecodeCompiler.h" |
|
dvander@0
|
19 |
#include "Scopes.h" |
|
dvander@0
|
20 |
#include "Modules.h" |
|
dvander@0
|
21 |
#include "Types.h" |
|
dvander@0
|
22 |
|
|
dvander@0
|
23 |
using namespace jc; |
|
dvander@0
|
24 |
|
|
dvander@0
|
25 |
typedef BytecodeEmitter::Label Label; |
|
dvander@0
|
26 |
|
|
dvander@0
|
27 |
#define __ emitter_. |
|
dvander@0
|
28 |
|
|
dvander@0
|
29 |
BytecodeCompiler::BytecodeCompiler(ParseTree *tree) |
|
dvander@1
|
30 |
: tree_(tree), |
|
dvander@1
|
31 |
scope_(NULL) |
|
dvander@0
|
32 |
{ |
|
dvander@0
|
33 |
} |
|
dvander@0
|
34 |
|
|
dvander@0
|
35 |
static inline TokenKind |
|
dvander@0
|
36 |
ToCompare(Expression *expr) |
|
dvander@0
|
37 |
{ |
|
dvander@0
|
38 |
if (expr->isBinaryExpression()) { |
|
dvander@0
|
39 |
BinaryExpression *b = expr->toBinaryExpression(); |
|
dvander@0
|
40 |
if (b->token() >= TOK_EQUALS && b->token() <= TOK_GE) |
|
dvander@0
|
41 |
return b->token(); |
|
dvander@0
|
42 |
} |
|
dvander@0
|
43 |
return TOK_EOF; |
|
dvander@0
|
44 |
} |
|
dvander@0
|
45 |
|
|
dvander@0
|
46 |
static inline Opcode |
|
dvander@0
|
47 |
CompareTokenToJump(TokenKind kind) |
|
dvander@0
|
48 |
{ |
|
dvander@0
|
49 |
switch (kind) { |
|
dvander@0
|
50 |
case TOK_EQUALS: |
|
dvander@0
|
51 |
return OP_JEQ; |
|
dvander@0
|
52 |
case TOK_NOTEQUALS: |
|
dvander@0
|
53 |
return OP_JNE; |
|
dvander@0
|
54 |
case TOK_GT: |
|
dvander@0
|
55 |
return OP_JG; |
|
dvander@0
|
56 |
case TOK_GE: |
|
dvander@0
|
57 |
return OP_JGE; |
|
dvander@0
|
58 |
case TOK_LT: |
|
dvander@0
|
59 |
return OP_JL; |
|
dvander@0
|
60 |
case TOK_LE: |
|
dvander@0
|
61 |
return OP_JLE; |
|
dvander@0
|
62 |
} |
|
dvander@0
|
63 |
assert(false); |
|
dvander@0
|
64 |
return OP_NOP; |
|
dvander@0
|
65 |
} |
|
dvander@0
|
66 |
|
|
dvander@0
|
67 |
static inline Opcode |
|
dvander@0
|
68 |
TokenToOpcode(TokenKind kind) |
|
dvander@0
|
69 |
{ |
|
dvander@0
|
70 |
switch (kind) { |
|
dvander@0
|
71 |
case TOK_PLUS: |
|
dvander@0
|
72 |
return OP_ADD; |
|
dvander@0
|
73 |
case TOK_MINUS: |
|
dvander@0
|
74 |
return OP_SUB; |
|
dvander@0
|
75 |
case TOK_STAR: |
|
dvander@0
|
76 |
return OP_MUL; |
|
dvander@0
|
77 |
case TOK_SLASH: |
|
dvander@0
|
78 |
return OP_DIV; |
|
dvander@0
|
79 |
} |
|
dvander@0
|
80 |
assert(false); |
|
dvander@0
|
81 |
return OP_NOP; |
|
dvander@0
|
82 |
} |
|
dvander@0
|
83 |
|
|
dvander@0
|
84 |
void |
|
dvander@1
|
85 |
BytecodeCompiler::leaveScope(Scope *scope) |
|
dvander@1
|
86 |
{ |
|
dvander@1
|
87 |
if (!scope) |
|
dvander@1
|
88 |
return; |
|
dvander@1
|
89 |
|
|
dvander@1
|
90 |
if (Variable *var = scope->firstUnsafeArray()) |
|
dvander@1
|
91 |
__ unwind(var->slot()); |
|
dvander@1
|
92 |
} |
|
dvander@1
|
93 |
|
|
dvander@1
|
94 |
void |
|
dvander@0
|
95 |
BytecodeCompiler::visit(NameProxy *name) |
|
dvander@0
|
96 |
{ |
|
dvander@0
|
97 |
Variable *var = name->binding()->toVariable(); |
|
dvander@0
|
98 |
|
|
dvander@0
|
99 |
if (var->location() == Variable::STACK) { |
|
dvander@0
|
100 |
__ getlocal(var->slot()); |
|
dvander@0
|
101 |
} else { |
|
dvander@0
|
102 |
assert(var->location() == Variable::PARAMETER); |
|
dvander@0
|
103 |
__ getarg(var->slot()); |
|
dvander@0
|
104 |
} |
|
dvander@0
|
105 |
} |
|
dvander@0
|
106 |
|
|
dvander@0
|
107 |
void |
|
dvander@0
|
108 |
BytecodeCompiler::visit(ExpressionStatement *node) |
|
dvander@0
|
109 |
{ |
|
dvander@0
|
110 |
// Expressions leave their value on the top of the stack, so we make sure |
|
dvander@0
|
111 |
// to balance the stack if they're used as a statement. |
|
dvander@0
|
112 |
node->expression()->accept(this); |
|
dvander@0
|
113 |
__ pop(); |
|
dvander@0
|
114 |
} |
|
dvander@0
|
115 |
|
|
dvander@0
|
116 |
void |
|
dvander@0
|
117 |
BytecodeCompiler::visit(Assignment *node) |
|
dvander@0
|
118 |
{ |
|
dvander@0
|
119 |
if (node->lvalue()->isNameProxy()) { |
|
dvander@0
|
120 |
NameProxy *proxy = node->lvalue()->toNameProxy(); |
|
dvander@0
|
121 |
Variable *var = proxy->binding()->toVariable(); |
|
dvander@0
|
122 |
|
|
dvander@0
|
123 |
node->expression()->accept(this); |
|
dvander@0
|
124 |
if (var->location() == Variable::STACK) { |
|
dvander@0
|
125 |
__ setlocal(var->slot()); |
|
dvander@0
|
126 |
} else { |
|
dvander@0
|
127 |
assert(var->location() == Variable::PARAMETER); |
|
dvander@0
|
128 |
__ setarg(var->slot()); |
|
dvander@0
|
129 |
} |
|
dvander@0
|
130 |
} else if (node->lvalue()->isIndexExpression()) { |
|
dvander@0
|
131 |
IndexExpression *index = node->lvalue()->toIndexExpression(); |
|
dvander@0
|
132 |
|
|
dvander@0
|
133 |
index->left()->accept(this); |
|
dvander@0
|
134 |
index->right()->accept(this); |
|
dvander@0
|
135 |
__ bounds_sta(); |
|
dvander@0
|
136 |
node->expression()->accept(this); |
|
dvander@0
|
137 |
__ st_sta_i(); |
|
dvander@0
|
138 |
} |
|
dvander@0
|
139 |
} |
|
dvander@0
|
140 |
|
|
dvander@0
|
141 |
void |
|
dvander@0
|
142 |
BytecodeCompiler::visit(BinaryExpression *node) |
|
dvander@0
|
143 |
{ |
|
dvander@0
|
144 |
node->left()->accept(this); |
|
dvander@0
|
145 |
node->right()->accept(this); |
|
dvander@0
|
146 |
|
|
dvander@0
|
147 |
Opcode op = TokenToOpcode(node->token()); |
|
dvander@0
|
148 |
__ binary(op); |
|
dvander@0
|
149 |
} |
|
dvander@0
|
150 |
|
|
dvander@0
|
151 |
void |
|
dvander@0
|
152 |
BytecodeCompiler::visit(IndexExpression *node) |
|
dvander@0
|
153 |
{ |
|
dvander@0
|
154 |
node->left()->accept(this); |
|
dvander@0
|
155 |
node->right()->accept(this); |
|
dvander@0
|
156 |
__ bounds_sta(); |
|
dvander@0
|
157 |
|
|
dvander@0
|
158 |
if (node->type()->isArray()) |
|
dvander@0
|
159 |
__ ld_sta_p(); |
|
dvander@0
|
160 |
else |
|
dvander@0
|
161 |
__ ld_sta_i(); |
|
dvander@0
|
162 |
} |
|
dvander@0
|
163 |
|
|
dvander@0
|
164 |
void |
|
dvander@0
|
165 |
BytecodeCompiler::visit(ReturnStatement *node) |
|
dvander@0
|
166 |
{ |
|
dvander@0
|
167 |
if (node->expression()) |
|
dvander@0
|
168 |
node->expression()->accept(this); |
|
dvander@0
|
169 |
else |
|
dvander@0
|
170 |
__ int_(0); |
|
dvander@0
|
171 |
|
|
dvander@0
|
172 |
__ return_(); |
|
dvander@0
|
173 |
} |
|
dvander@0
|
174 |
|
|
dvander@0
|
175 |
void |
|
dvander@0
|
176 |
BytecodeCompiler::visitForTest(Expression *expression, Label *label, bool onTrue) |
|
dvander@0
|
177 |
{ |
|
dvander@0
|
178 |
TokenKind token = ToCompare(expression); |
|
dvander@0
|
179 |
if (token == TOK_EOF) { |
|
dvander@0
|
180 |
expression->accept(this); |
|
dvander@0
|
181 |
if (onTrue) |
|
dvander@0
|
182 |
__ j(OP_JT, label); |
|
dvander@0
|
183 |
else |
|
dvander@0
|
184 |
__ j(OP_JF, label); |
|
dvander@0
|
185 |
return; |
|
dvander@0
|
186 |
} |
|
dvander@0
|
187 |
|
|
dvander@0
|
188 |
Opcode op = CompareTokenToJump(token); |
|
dvander@0
|
189 |
if (!onTrue) |
|
dvander@0
|
190 |
op = Invert(op); |
|
dvander@0
|
191 |
|
|
dvander@0
|
192 |
assert(expression->isBinaryExpression()); |
|
dvander@0
|
193 |
BinaryExpression *binary = expression->toBinaryExpression(); |
|
dvander@0
|
194 |
binary->left()->accept(this); |
|
dvander@0
|
195 |
binary->right()->accept(this); |
|
dvander@0
|
196 |
__ j(op, label); |
|
dvander@0
|
197 |
} |
|
dvander@0
|
198 |
|
|
dvander@0
|
199 |
void |
|
dvander@0
|
200 |
BytecodeCompiler::visit(ForStatement *node) |
|
dvander@0
|
201 |
{ |
|
dvander@1
|
202 |
AutoEnterScope forScope(this, node->scope()); |
|
dvander@1
|
203 |
|
|
dvander@0
|
204 |
if (node->declaration()) |
|
dvander@0
|
205 |
node->declaration()->accept(this); |
|
dvander@0
|
206 |
|
|
dvander@0
|
207 |
Label header, test; |
|
dvander@0
|
208 |
if (node->condition()) |
|
dvander@0
|
209 |
__ jump(&test); |
|
dvander@0
|
210 |
|
|
dvander@0
|
211 |
__ bind(&header); |
|
dvander@0
|
212 |
node->body()->accept(this); |
|
dvander@0
|
213 |
|
|
dvander@0
|
214 |
if (node->update()) |
|
dvander@0
|
215 |
node->update()->accept(this); |
|
dvander@0
|
216 |
|
|
dvander@0
|
217 |
if (node->condition()) { |
|
dvander@0
|
218 |
__ bind(&test); |
|
dvander@0
|
219 |
visitForTest(node->condition(), &header, true); |
|
dvander@0
|
220 |
} else { |
|
dvander@0
|
221 |
__ jump(&header); |
|
dvander@0
|
222 |
} |
|
dvander@0
|
223 |
|
|
dvander@1
|
224 |
leaveScope(node->scope()); |
|
dvander@0
|
225 |
assert(__ stackDepth() == 0); |
|
dvander@0
|
226 |
} |
|
dvander@0
|
227 |
|
|
dvander@0
|
228 |
void |
|
dvander@0
|
229 |
BytecodeCompiler::visit(BlockStatement *node) |
|
dvander@0
|
230 |
{ |
|
dvander@1
|
231 |
AutoEnterScope blockScope(this, node->scope()); |
|
dvander@1
|
232 |
|
|
dvander@0
|
233 |
for (size_t i = 0; i < node->statements()->length(); i++) { |
|
dvander@0
|
234 |
Statement *statement = node->statements()->at(i); |
|
dvander@0
|
235 |
statement->accept(this); |
|
dvander@0
|
236 |
assert(__ stackDepth() == 0); |
|
dvander@0
|
237 |
} |
|
dvander@1
|
238 |
|
|
dvander@1
|
239 |
// We don't bother emitting an "unwind" instruction for function scopes, |
|
dvander@1
|
240 |
// since this is taken care of by the calling convention. |
|
dvander@1
|
241 |
if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION) |
|
dvander@1
|
242 |
leaveScope(node->scope()); |
|
dvander@0
|
243 |
} |
|
dvander@0
|
244 |
|
|
dvander@0
|
245 |
void |
|
dvander@0
|
246 |
BytecodeCompiler::visit(IntegerLiteralExpression *node) |
|
dvander@0
|
247 |
{ |
|
dvander@0
|
248 |
__ int_(node->value()); |
|
dvander@0
|
249 |
} |
|
dvander@0
|
250 |
|
|
dvander@0
|
251 |
void |
|
dvander@0
|
252 |
BytecodeCompiler::visit(VariableDeclaration *node) |
|
dvander@0
|
253 |
{ |
|
dvander@0
|
254 |
Variable *var = node->variable(); |
|
dvander@0
|
255 |
assert(var->location() == Variable::STACK); |
|
dvander@0
|
256 |
|
|
dvander@0
|
257 |
Type *type = var->type(); |
|
dvander@0
|
258 |
if (type->isArray()) { |
|
dvander@0
|
259 |
bool isConstant = true; |
|
dvander@0
|
260 |
for (Type *child = type; child->isArray(); child = child->contained()) { |
|
dvander@0
|
261 |
if (child->elements() == Type::UNKNOWN_SIZE) { |
|
dvander@0
|
262 |
isConstant = false; |
|
dvander@0
|
263 |
break; |
|
dvander@0
|
264 |
} |
|
dvander@0
|
265 |
} |
|
dvander@0
|
266 |
|
|
dvander@0
|
267 |
if (!isConstant) { |
|
dvander@0
|
268 |
for (size_t i = 0; i < node->postDimensions()->size(); i++) { |
|
dvander@0
|
269 |
Expression *expr = node->postDimensions()->at(i); |
|
dvander@0
|
270 |
expr->accept(this); |
|
dvander@0
|
271 |
} |
|
dvander@0
|
272 |
} |
|
dvander@0
|
273 |
|
|
dvander@0
|
274 |
__ stackarray(type); |
|
dvander@0
|
275 |
} else { |
|
dvander@0
|
276 |
if (node->initialization()) { |
|
dvander@0
|
277 |
node->initialization()->accept(this); |
|
dvander@0
|
278 |
} else { |
|
dvander@0
|
279 |
if (!node->postDimensions()) |
|
dvander@0
|
280 |
__ int_(0); |
|
dvander@0
|
281 |
} |
|
dvander@0
|
282 |
} |
|
dvander@0
|
283 |
__ setlocal(var->slot()); |
|
dvander@0
|
284 |
__ pop(); |
|
dvander@0
|
285 |
|
|
dvander@0
|
286 |
locals_[var->slot()] = var->type(); |
|
dvander@0
|
287 |
} |
|
dvander@0
|
288 |
|
|
dvander@0
|
289 |
void |
|
dvander@0
|
290 |
BytecodeCompiler::visit(CallExpression *node) |
|
dvander@0
|
291 |
{ |
|
dvander@0
|
292 |
NameProxy *fun = node->callee()->toNameProxy(); |
|
dvander@0
|
293 |
|
|
dvander@0
|
294 |
for (size_t i = 0; i < node->arguments()->size(); i++) { |
|
dvander@0
|
295 |
Expression *arg = node->arguments()->at(i); |
|
dvander@0
|
296 |
arg->accept(this); |
|
dvander@0
|
297 |
} |
|
dvander@0
|
298 |
|
|
dvander@0
|
299 |
__ callglobal(node->arguments()->size(), 0); |
|
dvander@0
|
300 |
} |
|
dvander@0
|
301 |
|
|
dvander@0
|
302 |
void |
|
dvander@0
|
303 |
BytecodeCompiler::visit(IfStatement *node) |
|
dvander@0
|
304 |
{ |
|
dvander@0
|
305 |
if (!node->ifFalse()) { |
|
dvander@0
|
306 |
Label fail; |
|
dvander@0
|
307 |
visitForTest(node->condition(), &fail, false); |
|
dvander@0
|
308 |
node->ifTrue()->accept(this); |
|
dvander@0
|
309 |
__ bind(&fail); |
|
dvander@0
|
310 |
} else { |
|
dvander@0
|
311 |
Label fail, join; |
|
dvander@0
|
312 |
visitForTest(node->condition(), &fail, false); |
|
dvander@0
|
313 |
node->ifTrue()->accept(this); |
|
dvander@0
|
314 |
__ jump(&join); |
|
dvander@0
|
315 |
__ bind(&fail); |
|
dvander@0
|
316 |
node->ifFalse()->accept(this); |
|
dvander@0
|
317 |
__ bind(&join); |
|
dvander@0
|
318 |
} |
|
dvander@0
|
319 |
} |
|
dvander@0
|
320 |
|
|
dvander@0
|
321 |
void |
|
dvander@0
|
322 |
BytecodeCompiler::visit(FunctionStatement *node) |
|
dvander@0
|
323 |
{ |
|
dvander@0
|
324 |
BytecodeCompiler child(tree_); |
|
dvander@0
|
325 |
Code *code = child.compileFunction(module_, node); |
|
dvander@0
|
326 |
|
|
dvander@0
|
327 |
assert(!module_->getFunction(node->fun()->slot())); |
|
dvander@0
|
328 |
module_->setFunction(node->fun()->slot(), code); |
|
dvander@0
|
329 |
} |
|
dvander@0
|
330 |
|
|
dvander@0
|
331 |
Code * |
|
dvander@0
|
332 |
BytecodeCompiler::compileFunction(Module *module, FunctionStatement *node) |
|
dvander@0
|
333 |
{ |
|
dvander@1
|
334 |
AutoEnterScope functionScope(this, node->scope()); |
|
dvander@1
|
335 |
|
|
dvander@0
|
336 |
locals_ = new Type *[node->scope()->maxContainedLocals()]; |
|
dvander@0
|
337 |
memset(locals_, 0, sizeof(Type *) * node->scope()->maxContainedLocals()); |
|
dvander@0
|
338 |
|
|
dvander@0
|
339 |
node->body()->accept(this); |
|
dvander@0
|
340 |
|
|
dvander@0
|
341 |
__ stop(); |
|
dvander@0
|
342 |
|
|
dvander@0
|
343 |
if (__ oom()) |
|
dvander@0
|
344 |
return false; |
|
dvander@0
|
345 |
|
|
dvander@0
|
346 |
bytecode *start = (bytecode *)malloc(__ length() * sizeof(bytecode)); |
|
dvander@0
|
347 |
memcpy(start, __ buffer(), __ length()); |
|
dvander@0
|
348 |
|
|
dvander@0
|
349 |
unsigned nargs = node->scope()->numArguments(); |
|
dvander@0
|
350 |
Type **args = new Type *[nargs]; |
|
dvander@0
|
351 |
for (size_t i = 0; i < node->scope()->numArguments(); i++) |
|
dvander@0
|
352 |
args[i] = node->scope()->getArgument(i)->type(); |
|
dvander@0
|
353 |
|
|
dvander@0
|
354 |
for (size_t i = 0; i < node->scope()->maxContainedLocals(); i++) |
|
dvander@0
|
355 |
assert(locals_[i]); |
|
dvander@0
|
356 |
|
|
dvander@0
|
357 |
Code *code = new Code(module, |
|
dvander@0
|
358 |
start, |
|
dvander@0
|
359 |
__ length(), |
|
dvander@0
|
360 |
args, |
|
dvander@0
|
361 |
nargs, |
|
dvander@0
|
362 |
locals_, |
|
dvander@0
|
363 |
node->scope()->maxContainedLocals(), |
|
dvander@0
|
364 |
__ maxStackDepth()); |
|
dvander@0
|
365 |
|
|
dvander@0
|
366 |
return code; |
|
dvander@0
|
367 |
} |
|
dvander@0
|
368 |
|
|
dvander@0
|
369 |
Module * |
|
dvander@0
|
370 |
BytecodeCompiler::compile() |
|
dvander@0
|
371 |
{ |
|
dvander@0
|
372 |
Code **functions = new Code *[tree_->scope()->numFunctions()]; |
|
dvander@0
|
373 |
memset(functions, 0, sizeof(Code *) * tree_->scope()->numFunctions()); |
|
dvander@0
|
374 |
|
|
dvander@0
|
375 |
module_ = new Module(functions, tree_->scope()->numFunctions()); |
|
dvander@0
|
376 |
|
|
dvander@0
|
377 |
for (size_t i = 0; i < tree_->statements()->length(); i++) { |
|
dvander@0
|
378 |
Statement *statement = tree_->statements()->at(i); |
|
dvander@0
|
379 |
statement->accept(this); |
|
dvander@0
|
380 |
} |
|
dvander@0
|
381 |
|
|
dvander@0
|
382 |
#ifndef NDEBUG |
|
dvander@0
|
383 |
for (size_t i = 0; i < tree_->scope()->numFunctions(); i++) |
|
dvander@0
|
384 |
assert(functions[i]); |
|
dvander@0
|
385 |
#endif |
|
dvander@0
|
386 |
|
|
dvander@0
|
387 |
return module_; |
|
dvander@0
|
388 |
} |