|
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@0
|
30 |
: tree_(tree) |
|
dvander@0
|
31 |
{ |
|
dvander@0
|
32 |
} |
|
dvander@0
|
33 |
|
|
dvander@0
|
34 |
static inline TokenKind |
|
dvander@0
|
35 |
ToCompare(Expression *expr) |
|
dvander@0
|
36 |
{ |
|
dvander@0
|
37 |
if (expr->isBinaryExpression()) { |
|
dvander@0
|
38 |
BinaryExpression *b = expr->toBinaryExpression(); |
|
dvander@0
|
39 |
if (b->token() >= TOK_EQUALS && b->token() <= TOK_GE) |
|
dvander@0
|
40 |
return b->token(); |
|
dvander@0
|
41 |
} |
|
dvander@0
|
42 |
return TOK_EOF; |
|
dvander@0
|
43 |
} |
|
dvander@0
|
44 |
|
|
dvander@0
|
45 |
static inline Opcode |
|
dvander@0
|
46 |
CompareTokenToJump(TokenKind kind) |
|
dvander@0
|
47 |
{ |
|
dvander@0
|
48 |
switch (kind) { |
|
dvander@0
|
49 |
case TOK_EQUALS: |
|
dvander@0
|
50 |
return OP_JEQ; |
|
dvander@0
|
51 |
case TOK_NOTEQUALS: |
|
dvander@0
|
52 |
return OP_JNE; |
|
dvander@0
|
53 |
case TOK_GT: |
|
dvander@0
|
54 |
return OP_JG; |
|
dvander@0
|
55 |
case TOK_GE: |
|
dvander@0
|
56 |
return OP_JGE; |
|
dvander@0
|
57 |
case TOK_LT: |
|
dvander@0
|
58 |
return OP_JL; |
|
dvander@0
|
59 |
case TOK_LE: |
|
dvander@0
|
60 |
return OP_JLE; |
|
dvander@0
|
61 |
} |
|
dvander@0
|
62 |
assert(false); |
|
dvander@0
|
63 |
return OP_NOP; |
|
dvander@0
|
64 |
} |
|
dvander@0
|
65 |
|
|
dvander@0
|
66 |
static inline Opcode |
|
dvander@0
|
67 |
TokenToOpcode(TokenKind kind) |
|
dvander@0
|
68 |
{ |
|
dvander@0
|
69 |
switch (kind) { |
|
dvander@0
|
70 |
case TOK_PLUS: |
|
dvander@0
|
71 |
return OP_ADD; |
|
dvander@0
|
72 |
case TOK_MINUS: |
|
dvander@0
|
73 |
return OP_SUB; |
|
dvander@0
|
74 |
case TOK_STAR: |
|
dvander@0
|
75 |
return OP_MUL; |
|
dvander@0
|
76 |
case TOK_SLASH: |
|
dvander@0
|
77 |
return OP_DIV; |
|
dvander@0
|
78 |
} |
|
dvander@0
|
79 |
assert(false); |
|
dvander@0
|
80 |
return OP_NOP; |
|
dvander@0
|
81 |
} |
|
dvander@0
|
82 |
|
|
dvander@0
|
83 |
void |
|
dvander@0
|
84 |
BytecodeCompiler::visit(NameProxy *name) |
|
dvander@0
|
85 |
{ |
|
dvander@0
|
86 |
Variable *var = name->binding()->toVariable(); |
|
dvander@0
|
87 |
|
|
dvander@0
|
88 |
if (var->location() == Variable::STACK) { |
|
dvander@0
|
89 |
__ getlocal(var->slot()); |
|
dvander@0
|
90 |
} else { |
|
dvander@0
|
91 |
assert(var->location() == Variable::PARAMETER); |
|
dvander@0
|
92 |
__ getarg(var->slot()); |
|
dvander@0
|
93 |
} |
|
dvander@0
|
94 |
} |
|
dvander@0
|
95 |
|
|
dvander@0
|
96 |
void |
|
dvander@0
|
97 |
BytecodeCompiler::visit(ExpressionStatement *node) |
|
dvander@0
|
98 |
{ |
|
dvander@0
|
99 |
// Expressions leave their value on the top of the stack, so we make sure |
|
dvander@0
|
100 |
// to balance the stack if they're used as a statement. |
|
dvander@0
|
101 |
node->expression()->accept(this); |
|
dvander@0
|
102 |
__ pop(); |
|
dvander@0
|
103 |
} |
|
dvander@0
|
104 |
|
|
dvander@0
|
105 |
void |
|
dvander@0
|
106 |
BytecodeCompiler::visit(Assignment *node) |
|
dvander@0
|
107 |
{ |
|
dvander@0
|
108 |
if (node->lvalue()->isNameProxy()) { |
|
dvander@0
|
109 |
NameProxy *proxy = node->lvalue()->toNameProxy(); |
|
dvander@0
|
110 |
Variable *var = proxy->binding()->toVariable(); |
|
dvander@0
|
111 |
|
|
dvander@0
|
112 |
node->expression()->accept(this); |
|
dvander@0
|
113 |
if (var->location() == Variable::STACK) { |
|
dvander@0
|
114 |
__ setlocal(var->slot()); |
|
dvander@0
|
115 |
} else { |
|
dvander@0
|
116 |
assert(var->location() == Variable::PARAMETER); |
|
dvander@0
|
117 |
__ setarg(var->slot()); |
|
dvander@0
|
118 |
} |
|
dvander@0
|
119 |
} else if (node->lvalue()->isIndexExpression()) { |
|
dvander@0
|
120 |
IndexExpression *index = node->lvalue()->toIndexExpression(); |
|
dvander@0
|
121 |
|
|
dvander@0
|
122 |
index->left()->accept(this); |
|
dvander@0
|
123 |
index->right()->accept(this); |
|
dvander@0
|
124 |
__ bounds_sta(); |
|
dvander@0
|
125 |
node->expression()->accept(this); |
|
dvander@0
|
126 |
__ st_sta_i(); |
|
dvander@0
|
127 |
} |
|
dvander@0
|
128 |
} |
|
dvander@0
|
129 |
|
|
dvander@0
|
130 |
void |
|
dvander@0
|
131 |
BytecodeCompiler::visit(BinaryExpression *node) |
|
dvander@0
|
132 |
{ |
|
dvander@0
|
133 |
node->left()->accept(this); |
|
dvander@0
|
134 |
node->right()->accept(this); |
|
dvander@0
|
135 |
|
|
dvander@0
|
136 |
Opcode op = TokenToOpcode(node->token()); |
|
dvander@0
|
137 |
__ binary(op); |
|
dvander@0
|
138 |
} |
|
dvander@0
|
139 |
|
|
dvander@0
|
140 |
void |
|
dvander@0
|
141 |
BytecodeCompiler::visit(IndexExpression *node) |
|
dvander@0
|
142 |
{ |
|
dvander@0
|
143 |
node->left()->accept(this); |
|
dvander@0
|
144 |
node->right()->accept(this); |
|
dvander@0
|
145 |
__ bounds_sta(); |
|
dvander@0
|
146 |
|
|
dvander@0
|
147 |
if (node->type()->isArray()) |
|
dvander@0
|
148 |
__ ld_sta_p(); |
|
dvander@0
|
149 |
else |
|
dvander@0
|
150 |
__ ld_sta_i(); |
|
dvander@0
|
151 |
} |
|
dvander@0
|
152 |
|
|
dvander@0
|
153 |
void |
|
dvander@0
|
154 |
BytecodeCompiler::visit(ReturnStatement *node) |
|
dvander@0
|
155 |
{ |
|
dvander@0
|
156 |
if (node->expression()) |
|
dvander@0
|
157 |
node->expression()->accept(this); |
|
dvander@0
|
158 |
else |
|
dvander@0
|
159 |
__ int_(0); |
|
dvander@0
|
160 |
|
|
dvander@0
|
161 |
__ return_(); |
|
dvander@0
|
162 |
} |
|
dvander@0
|
163 |
|
|
dvander@0
|
164 |
void |
|
dvander@0
|
165 |
BytecodeCompiler::visitForTest(Expression *expression, Label *label, bool onTrue) |
|
dvander@0
|
166 |
{ |
|
dvander@0
|
167 |
TokenKind token = ToCompare(expression); |
|
dvander@0
|
168 |
if (token == TOK_EOF) { |
|
dvander@0
|
169 |
expression->accept(this); |
|
dvander@0
|
170 |
if (onTrue) |
|
dvander@0
|
171 |
__ j(OP_JT, label); |
|
dvander@0
|
172 |
else |
|
dvander@0
|
173 |
__ j(OP_JF, label); |
|
dvander@0
|
174 |
return; |
|
dvander@0
|
175 |
} |
|
dvander@0
|
176 |
|
|
dvander@0
|
177 |
Opcode op = CompareTokenToJump(token); |
|
dvander@0
|
178 |
if (!onTrue) |
|
dvander@0
|
179 |
op = Invert(op); |
|
dvander@0
|
180 |
|
|
dvander@0
|
181 |
assert(expression->isBinaryExpression()); |
|
dvander@0
|
182 |
BinaryExpression *binary = expression->toBinaryExpression(); |
|
dvander@0
|
183 |
binary->left()->accept(this); |
|
dvander@0
|
184 |
binary->right()->accept(this); |
|
dvander@0
|
185 |
__ j(op, label); |
|
dvander@0
|
186 |
} |
|
dvander@0
|
187 |
|
|
dvander@0
|
188 |
void |
|
dvander@0
|
189 |
BytecodeCompiler::visit(ForStatement *node) |
|
dvander@0
|
190 |
{ |
|
dvander@0
|
191 |
if (node->declaration()) |
|
dvander@0
|
192 |
node->declaration()->accept(this); |
|
dvander@0
|
193 |
|
|
dvander@0
|
194 |
Label header, test; |
|
dvander@0
|
195 |
if (node->condition()) |
|
dvander@0
|
196 |
__ jump(&test); |
|
dvander@0
|
197 |
|
|
dvander@0
|
198 |
__ bind(&header); |
|
dvander@0
|
199 |
node->body()->accept(this); |
|
dvander@0
|
200 |
|
|
dvander@0
|
201 |
if (node->update()) |
|
dvander@0
|
202 |
node->update()->accept(this); |
|
dvander@0
|
203 |
|
|
dvander@0
|
204 |
if (node->condition()) { |
|
dvander@0
|
205 |
__ bind(&test); |
|
dvander@0
|
206 |
visitForTest(node->condition(), &header, true); |
|
dvander@0
|
207 |
} else { |
|
dvander@0
|
208 |
__ jump(&header); |
|
dvander@0
|
209 |
} |
|
dvander@0
|
210 |
|
|
dvander@0
|
211 |
assert(__ stackDepth() == 0); |
|
dvander@0
|
212 |
} |
|
dvander@0
|
213 |
|
|
dvander@0
|
214 |
void |
|
dvander@0
|
215 |
BytecodeCompiler::visit(BlockStatement *node) |
|
dvander@0
|
216 |
{ |
|
dvander@0
|
217 |
for (size_t i = 0; i < node->statements()->length(); i++) { |
|
dvander@0
|
218 |
Statement *statement = node->statements()->at(i); |
|
dvander@0
|
219 |
statement->accept(this); |
|
dvander@0
|
220 |
assert(__ stackDepth() == 0); |
|
dvander@0
|
221 |
} |
|
dvander@0
|
222 |
} |
|
dvander@0
|
223 |
|
|
dvander@0
|
224 |
void |
|
dvander@0
|
225 |
BytecodeCompiler::visit(IntegerLiteralExpression *node) |
|
dvander@0
|
226 |
{ |
|
dvander@0
|
227 |
__ int_(node->value()); |
|
dvander@0
|
228 |
} |
|
dvander@0
|
229 |
|
|
dvander@0
|
230 |
void |
|
dvander@0
|
231 |
BytecodeCompiler::visit(VariableDeclaration *node) |
|
dvander@0
|
232 |
{ |
|
dvander@0
|
233 |
Variable *var = node->variable(); |
|
dvander@0
|
234 |
assert(var->location() == Variable::STACK); |
|
dvander@0
|
235 |
|
|
dvander@0
|
236 |
Type *type = var->type(); |
|
dvander@0
|
237 |
if (type->isArray()) { |
|
dvander@0
|
238 |
bool isConstant = true; |
|
dvander@0
|
239 |
for (Type *child = type; child->isArray(); child = child->contained()) { |
|
dvander@0
|
240 |
if (child->elements() == Type::UNKNOWN_SIZE) { |
|
dvander@0
|
241 |
isConstant = false; |
|
dvander@0
|
242 |
break; |
|
dvander@0
|
243 |
} |
|
dvander@0
|
244 |
} |
|
dvander@0
|
245 |
|
|
dvander@0
|
246 |
if (!isConstant) { |
|
dvander@0
|
247 |
for (size_t i = 0; i < node->postDimensions()->size(); i++) { |
|
dvander@0
|
248 |
Expression *expr = node->postDimensions()->at(i); |
|
dvander@0
|
249 |
expr->accept(this); |
|
dvander@0
|
250 |
} |
|
dvander@0
|
251 |
} |
|
dvander@0
|
252 |
|
|
dvander@0
|
253 |
__ stackarray(type); |
|
dvander@0
|
254 |
} else { |
|
dvander@0
|
255 |
if (node->initialization()) { |
|
dvander@0
|
256 |
node->initialization()->accept(this); |
|
dvander@0
|
257 |
} else { |
|
dvander@0
|
258 |
if (!node->postDimensions()) |
|
dvander@0
|
259 |
__ int_(0); |
|
dvander@0
|
260 |
} |
|
dvander@0
|
261 |
} |
|
dvander@0
|
262 |
__ setlocal(var->slot()); |
|
dvander@0
|
263 |
__ pop(); |
|
dvander@0
|
264 |
|
|
dvander@0
|
265 |
locals_[var->slot()] = var->type(); |
|
dvander@0
|
266 |
} |
|
dvander@0
|
267 |
|
|
dvander@0
|
268 |
void |
|
dvander@0
|
269 |
BytecodeCompiler::visit(CallExpression *node) |
|
dvander@0
|
270 |
{ |
|
dvander@0
|
271 |
NameProxy *fun = node->callee()->toNameProxy(); |
|
dvander@0
|
272 |
|
|
dvander@0
|
273 |
for (size_t i = 0; i < node->arguments()->size(); i++) { |
|
dvander@0
|
274 |
Expression *arg = node->arguments()->at(i); |
|
dvander@0
|
275 |
arg->accept(this); |
|
dvander@0
|
276 |
} |
|
dvander@0
|
277 |
|
|
dvander@0
|
278 |
__ callglobal(node->arguments()->size(), 0); |
|
dvander@0
|
279 |
} |
|
dvander@0
|
280 |
|
|
dvander@0
|
281 |
void |
|
dvander@0
|
282 |
BytecodeCompiler::visit(IfStatement *node) |
|
dvander@0
|
283 |
{ |
|
dvander@0
|
284 |
if (!node->ifFalse()) { |
|
dvander@0
|
285 |
Label fail; |
|
dvander@0
|
286 |
visitForTest(node->condition(), &fail, false); |
|
dvander@0
|
287 |
node->ifTrue()->accept(this); |
|
dvander@0
|
288 |
__ bind(&fail); |
|
dvander@0
|
289 |
} else { |
|
dvander@0
|
290 |
Label fail, join; |
|
dvander@0
|
291 |
visitForTest(node->condition(), &fail, false); |
|
dvander@0
|
292 |
node->ifTrue()->accept(this); |
|
dvander@0
|
293 |
__ jump(&join); |
|
dvander@0
|
294 |
__ bind(&fail); |
|
dvander@0
|
295 |
node->ifFalse()->accept(this); |
|
dvander@0
|
296 |
__ bind(&join); |
|
dvander@0
|
297 |
} |
|
dvander@0
|
298 |
} |
|
dvander@0
|
299 |
|
|
dvander@0
|
300 |
void |
|
dvander@0
|
301 |
BytecodeCompiler::visit(FunctionStatement *node) |
|
dvander@0
|
302 |
{ |
|
dvander@0
|
303 |
BytecodeCompiler child(tree_); |
|
dvander@0
|
304 |
Code *code = child.compileFunction(module_, node); |
|
dvander@0
|
305 |
|
|
dvander@0
|
306 |
assert(!module_->getFunction(node->fun()->slot())); |
|
dvander@0
|
307 |
module_->setFunction(node->fun()->slot(), code); |
|
dvander@0
|
308 |
} |
|
dvander@0
|
309 |
|
|
dvander@0
|
310 |
Code * |
|
dvander@0
|
311 |
BytecodeCompiler::compileFunction(Module *module, FunctionStatement *node) |
|
dvander@0
|
312 |
{ |
|
dvander@0
|
313 |
locals_ = new Type *[node->scope()->maxContainedLocals()]; |
|
dvander@0
|
314 |
memset(locals_, 0, sizeof(Type *) * node->scope()->maxContainedLocals()); |
|
dvander@0
|
315 |
|
|
dvander@0
|
316 |
node->body()->accept(this); |
|
dvander@0
|
317 |
|
|
dvander@0
|
318 |
__ stop(); |
|
dvander@0
|
319 |
|
|
dvander@0
|
320 |
if (__ oom()) |
|
dvander@0
|
321 |
return false; |
|
dvander@0
|
322 |
|
|
dvander@0
|
323 |
bytecode *start = (bytecode *)malloc(__ length() * sizeof(bytecode)); |
|
dvander@0
|
324 |
memcpy(start, __ buffer(), __ length()); |
|
dvander@0
|
325 |
|
|
dvander@0
|
326 |
unsigned nargs = node->scope()->numArguments(); |
|
dvander@0
|
327 |
Type **args = new Type *[nargs]; |
|
dvander@0
|
328 |
for (size_t i = 0; i < node->scope()->numArguments(); i++) |
|
dvander@0
|
329 |
args[i] = node->scope()->getArgument(i)->type(); |
|
dvander@0
|
330 |
|
|
dvander@0
|
331 |
for (size_t i = 0; i < node->scope()->maxContainedLocals(); i++) |
|
dvander@0
|
332 |
assert(locals_[i]); |
|
dvander@0
|
333 |
|
|
dvander@0
|
334 |
Code *code = new Code(module, |
|
dvander@0
|
335 |
start, |
|
dvander@0
|
336 |
__ length(), |
|
dvander@0
|
337 |
args, |
|
dvander@0
|
338 |
nargs, |
|
dvander@0
|
339 |
locals_, |
|
dvander@0
|
340 |
node->scope()->maxContainedLocals(), |
|
dvander@0
|
341 |
__ maxStackDepth()); |
|
dvander@0
|
342 |
|
|
dvander@0
|
343 |
return code; |
|
dvander@0
|
344 |
} |
|
dvander@0
|
345 |
|
|
dvander@0
|
346 |
Module * |
|
dvander@0
|
347 |
BytecodeCompiler::compile() |
|
dvander@0
|
348 |
{ |
|
dvander@0
|
349 |
Code **functions = new Code *[tree_->scope()->numFunctions()]; |
|
dvander@0
|
350 |
memset(functions, 0, sizeof(Code *) * tree_->scope()->numFunctions()); |
|
dvander@0
|
351 |
|
|
dvander@0
|
352 |
module_ = new Module(functions, tree_->scope()->numFunctions()); |
|
dvander@0
|
353 |
|
|
dvander@0
|
354 |
for (size_t i = 0; i < tree_->statements()->length(); i++) { |
|
dvander@0
|
355 |
Statement *statement = tree_->statements()->at(i); |
|
dvander@0
|
356 |
statement->accept(this); |
|
dvander@0
|
357 |
} |
|
dvander@0
|
358 |
|
|
dvander@0
|
359 |
#ifndef NDEBUG |
|
dvander@0
|
360 |
for (size_t i = 0; i < tree_->scope()->numFunctions(); i++) |
|
dvander@0
|
361 |
assert(functions[i]); |
|
dvander@0
|
362 |
#endif |
|
dvander@0
|
363 |
|
|
dvander@0
|
364 |
return module_; |
|
dvander@0
|
365 |
} |