|
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@10
|
31 |
scope_(NULL), |
|
dvander@10
|
32 |
loop_(NULL) |
|
dvander@0
|
33 |
{ |
|
dvander@0
|
34 |
} |
|
dvander@0
|
35 |
|
|
dvander@0
|
36 |
static inline TokenKind |
|
dvander@0
|
37 |
ToCompare(Expression *expr) |
|
dvander@0
|
38 |
{ |
|
dvander@0
|
39 |
if (expr->isBinaryExpression()) { |
|
dvander@0
|
40 |
BinaryExpression *b = expr->toBinaryExpression(); |
|
dvander@0
|
41 |
if (b->token() >= TOK_EQUALS && b->token() <= TOK_GE) |
|
dvander@0
|
42 |
return b->token(); |
|
dvander@0
|
43 |
} |
|
dvander@0
|
44 |
return TOK_EOF; |
|
dvander@0
|
45 |
} |
|
dvander@0
|
46 |
|
|
dvander@0
|
47 |
static inline Opcode |
|
dvander@0
|
48 |
CompareTokenToJump(TokenKind kind) |
|
dvander@0
|
49 |
{ |
|
dvander@0
|
50 |
switch (kind) { |
|
dvander@0
|
51 |
case TOK_EQUALS: |
|
dvander@0
|
52 |
return OP_JEQ; |
|
dvander@0
|
53 |
case TOK_NOTEQUALS: |
|
dvander@0
|
54 |
return OP_JNE; |
|
dvander@0
|
55 |
case TOK_GT: |
|
dvander@0
|
56 |
return OP_JG; |
|
dvander@0
|
57 |
case TOK_GE: |
|
dvander@0
|
58 |
return OP_JGE; |
|
dvander@0
|
59 |
case TOK_LT: |
|
dvander@0
|
60 |
return OP_JL; |
|
dvander@0
|
61 |
case TOK_LE: |
|
dvander@0
|
62 |
return OP_JLE; |
|
dvander@0
|
63 |
} |
|
dvander@0
|
64 |
assert(false); |
|
dvander@0
|
65 |
return OP_NOP; |
|
dvander@0
|
66 |
} |
|
dvander@0
|
67 |
|
|
dvander@0
|
68 |
static inline Opcode |
|
dvander@0
|
69 |
TokenToOpcode(TokenKind kind) |
|
dvander@0
|
70 |
{ |
|
dvander@0
|
71 |
switch (kind) { |
|
dvander@0
|
72 |
case TOK_PLUS: |
|
dvander@0
|
73 |
return OP_ADD; |
|
dvander@0
|
74 |
case TOK_MINUS: |
|
dvander@0
|
75 |
return OP_SUB; |
|
dvander@0
|
76 |
case TOK_STAR: |
|
dvander@0
|
77 |
return OP_MUL; |
|
dvander@0
|
78 |
case TOK_SLASH: |
|
dvander@0
|
79 |
return OP_DIV; |
|
dvander@8
|
80 |
case TOK_SHR: |
|
dvander@8
|
81 |
return OP_SHR; |
|
dvander@8
|
82 |
case TOK_USHR: |
|
dvander@8
|
83 |
return OP_USHR; |
|
dvander@8
|
84 |
case TOK_SHL: |
|
dvander@8
|
85 |
return OP_SHL; |
|
dvander@8
|
86 |
case TOK_BITAND: |
|
dvander@8
|
87 |
return OP_BITAND; |
|
dvander@8
|
88 |
case TOK_BITOR: |
|
dvander@8
|
89 |
return OP_BITOR; |
|
dvander@8
|
90 |
case TOK_BITXOR: |
|
dvander@8
|
91 |
return OP_BITXOR; |
|
dvander@0
|
92 |
} |
|
dvander@0
|
93 |
assert(false); |
|
dvander@0
|
94 |
return OP_NOP; |
|
dvander@0
|
95 |
} |
|
dvander@0
|
96 |
|
|
dvander@0
|
97 |
void |
|
dvander@1
|
98 |
BytecodeCompiler::leaveScope(Scope *scope) |
|
dvander@1
|
99 |
{ |
|
dvander@1
|
100 |
if (!scope) |
|
dvander@1
|
101 |
return; |
|
dvander@1
|
102 |
|
|
dvander@1
|
103 |
if (Variable *var = scope->firstUnsafeArray()) |
|
dvander@1
|
104 |
__ unwind(var->slot()); |
|
dvander@1
|
105 |
} |
|
dvander@1
|
106 |
|
|
dvander@1
|
107 |
void |
|
dvander@10
|
108 |
BytecodeCompiler::unwindTo(Scope *scope) |
|
dvander@10
|
109 |
{ |
|
dvander@10
|
110 |
for (Scope *current = scope_; current != scope; current = current->enclosing()) { |
|
dvander@10
|
111 |
if (Variable *var = current->firstUnsafeArray()) |
|
dvander@10
|
112 |
__ unwind(var->slot()); |
|
dvander@10
|
113 |
} |
|
dvander@10
|
114 |
} |
|
dvander@10
|
115 |
|
|
dvander@10
|
116 |
void |
|
dvander@0
|
117 |
BytecodeCompiler::visit(NameProxy *name) |
|
dvander@0
|
118 |
{ |
|
dvander@2
|
119 |
switch (name->binding()->kind()) { |
|
dvander@2
|
120 |
case BoundName::VARIABLE: |
|
dvander@2
|
121 |
{ |
|
dvander@2
|
122 |
Variable *var = name->binding()->toVariable(); |
|
dvander@0
|
123 |
|
|
dvander@2
|
124 |
if (var->location() == Variable::STACK) { |
|
dvander@2
|
125 |
__ getlocal(var->slot()); |
|
dvander@2
|
126 |
} else { |
|
dvander@2
|
127 |
assert(var->location() == Variable::PARAMETER); |
|
dvander@2
|
128 |
__ getarg(var->slot()); |
|
dvander@2
|
129 |
} |
|
dvander@2
|
130 |
break; |
|
dvander@2
|
131 |
} |
|
dvander@2
|
132 |
|
|
dvander@2
|
133 |
default: |
|
dvander@2
|
134 |
{ |
|
dvander@2
|
135 |
NamedConstant *constant = name->binding()->toNamedConstant(); |
|
dvander@2
|
136 |
__ int_(constant->value().toInt()); |
|
dvander@2
|
137 |
break; |
|
dvander@2
|
138 |
} |
|
dvander@0
|
139 |
} |
|
dvander@0
|
140 |
} |
|
dvander@0
|
141 |
|
|
dvander@0
|
142 |
void |
|
dvander@0
|
143 |
BytecodeCompiler::visit(ExpressionStatement *node) |
|
dvander@0
|
144 |
{ |
|
dvander@0
|
145 |
// Expressions leave their value on the top of the stack, so we make sure |
|
dvander@0
|
146 |
// to balance the stack if they're used as a statement. |
|
dvander@0
|
147 |
node->expression()->accept(this); |
|
dvander@0
|
148 |
__ pop(); |
|
dvander@0
|
149 |
} |
|
dvander@0
|
150 |
|
|
dvander@0
|
151 |
void |
|
dvander@0
|
152 |
BytecodeCompiler::visit(Assignment *node) |
|
dvander@0
|
153 |
{ |
|
dvander@0
|
154 |
if (node->lvalue()->isNameProxy()) { |
|
dvander@0
|
155 |
NameProxy *proxy = node->lvalue()->toNameProxy(); |
|
dvander@0
|
156 |
Variable *var = proxy->binding()->toVariable(); |
|
dvander@0
|
157 |
|
|
dvander@0
|
158 |
node->expression()->accept(this); |
|
dvander@0
|
159 |
if (var->location() == Variable::STACK) { |
|
dvander@0
|
160 |
__ setlocal(var->slot()); |
|
dvander@0
|
161 |
} else { |
|
dvander@0
|
162 |
assert(var->location() == Variable::PARAMETER); |
|
dvander@0
|
163 |
__ setarg(var->slot()); |
|
dvander@0
|
164 |
} |
|
dvander@0
|
165 |
} else if (node->lvalue()->isIndexExpression()) { |
|
dvander@0
|
166 |
IndexExpression *index = node->lvalue()->toIndexExpression(); |
|
dvander@0
|
167 |
|
|
dvander@0
|
168 |
index->left()->accept(this); |
|
dvander@0
|
169 |
index->right()->accept(this); |
|
dvander@0
|
170 |
__ bounds_sta(); |
|
dvander@0
|
171 |
node->expression()->accept(this); |
|
dvander@7
|
172 |
if (index->left()->type()->contained()->isFloat()) { |
|
dvander@7
|
173 |
__ setarray_f(); |
|
dvander@7
|
174 |
} else { |
|
dvander@7
|
175 |
assert(index->left()->type()->contained()->isInt()); |
|
dvander@7
|
176 |
__ setarray_i(); |
|
dvander@7
|
177 |
} |
|
dvander@0
|
178 |
} |
|
dvander@0
|
179 |
} |
|
dvander@0
|
180 |
|
|
dvander@0
|
181 |
void |
|
dvander@4
|
182 |
BytecodeCompiler::visitForALU(Type *needed, Expression *node) |
|
dvander@4
|
183 |
{ |
|
dvander@4
|
184 |
node->accept(this); |
|
dvander@4
|
185 |
if (needed->isFloat() && !node->type()->isFloat()) |
|
dvander@4
|
186 |
__ cvt_i2f(); |
|
dvander@4
|
187 |
} |
|
dvander@4
|
188 |
|
|
dvander@4
|
189 |
void |
|
dvander@0
|
190 |
BytecodeCompiler::visit(BinaryExpression *node) |
|
dvander@0
|
191 |
{ |
|
dvander@4
|
192 |
visitForALU(node->type(), node->left()); |
|
dvander@4
|
193 |
visitForALU(node->type(), node->right()); |
|
dvander@0
|
194 |
|
|
dvander@0
|
195 |
Opcode op = TokenToOpcode(node->token()); |
|
dvander@4
|
196 |
if (node->type()->isFloat()) |
|
dvander@4
|
197 |
op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD)); |
|
dvander@0
|
198 |
__ binary(op); |
|
dvander@0
|
199 |
} |
|
dvander@0
|
200 |
|
|
dvander@0
|
201 |
void |
|
dvander@0
|
202 |
BytecodeCompiler::visit(IndexExpression *node) |
|
dvander@0
|
203 |
{ |
|
dvander@0
|
204 |
node->left()->accept(this); |
|
dvander@0
|
205 |
node->right()->accept(this); |
|
dvander@0
|
206 |
__ bounds_sta(); |
|
dvander@0
|
207 |
|
|
dvander@7
|
208 |
if (node->type()->isArray()) { |
|
dvander@6
|
209 |
__ getarray_p(); |
|
dvander@7
|
210 |
} else if (node->type()->isFloat()) { |
|
dvander@7
|
211 |
__ getarray_f(); |
|
dvander@7
|
212 |
} else { |
|
dvander@6
|
213 |
__ getarray_i(); |
|
dvander@7
|
214 |
assert(node->type()->isInt()); |
|
dvander@7
|
215 |
} |
|
dvander@0
|
216 |
} |
|
dvander@0
|
217 |
|
|
dvander@0
|
218 |
void |
|
dvander@0
|
219 |
BytecodeCompiler::visit(ReturnStatement *node) |
|
dvander@0
|
220 |
{ |
|
dvander@0
|
221 |
if (node->expression()) |
|
dvander@0
|
222 |
node->expression()->accept(this); |
|
dvander@0
|
223 |
else |
|
dvander@0
|
224 |
__ int_(0); |
|
dvander@0
|
225 |
|
|
dvander@0
|
226 |
__ return_(); |
|
dvander@0
|
227 |
} |
|
dvander@0
|
228 |
|
|
dvander@0
|
229 |
void |
|
dvander@0
|
230 |
BytecodeCompiler::visitForTest(Expression *expression, Label *label, bool onTrue) |
|
dvander@0
|
231 |
{ |
|
dvander@0
|
232 |
TokenKind token = ToCompare(expression); |
|
dvander@0
|
233 |
if (token == TOK_EOF) { |
|
dvander@0
|
234 |
expression->accept(this); |
|
dvander@0
|
235 |
if (onTrue) |
|
dvander@0
|
236 |
__ j(OP_JT, label); |
|
dvander@0
|
237 |
else |
|
dvander@0
|
238 |
__ j(OP_JF, label); |
|
dvander@0
|
239 |
return; |
|
dvander@0
|
240 |
} |
|
dvander@0
|
241 |
|
|
dvander@0
|
242 |
Opcode op = CompareTokenToJump(token); |
|
dvander@0
|
243 |
if (!onTrue) |
|
dvander@0
|
244 |
op = Invert(op); |
|
dvander@0
|
245 |
|
|
dvander@0
|
246 |
assert(expression->isBinaryExpression()); |
|
dvander@0
|
247 |
BinaryExpression *binary = expression->toBinaryExpression(); |
|
dvander@0
|
248 |
binary->left()->accept(this); |
|
dvander@0
|
249 |
binary->right()->accept(this); |
|
dvander@0
|
250 |
__ j(op, label); |
|
dvander@0
|
251 |
} |
|
dvander@0
|
252 |
|
|
dvander@0
|
253 |
void |
|
dvander@0
|
254 |
BytecodeCompiler::visit(ForStatement *node) |
|
dvander@0
|
255 |
{ |
|
dvander@1
|
256 |
AutoEnterScope forScope(this, node->scope()); |
|
dvander@1
|
257 |
|
|
dvander@10
|
258 |
Label join, update; |
|
dvander@10
|
259 |
|
|
dvander@10
|
260 |
LoopScope loop(scope_, &join, &update, &loop_); |
|
dvander@10
|
261 |
|
|
dvander@0
|
262 |
if (node->declaration()) |
|
dvander@0
|
263 |
node->declaration()->accept(this); |
|
dvander@0
|
264 |
|
|
dvander@0
|
265 |
Label header, test; |
|
dvander@0
|
266 |
if (node->condition()) |
|
dvander@0
|
267 |
__ jump(&test); |
|
dvander@0
|
268 |
|
|
dvander@0
|
269 |
__ bind(&header); |
|
dvander@0
|
270 |
node->body()->accept(this); |
|
dvander@0
|
271 |
|
|
dvander@10
|
272 |
__ bind(&update); |
|
dvander@0
|
273 |
if (node->update()) |
|
dvander@0
|
274 |
node->update()->accept(this); |
|
dvander@0
|
275 |
|
|
dvander@0
|
276 |
if (node->condition()) { |
|
dvander@0
|
277 |
__ bind(&test); |
|
dvander@0
|
278 |
visitForTest(node->condition(), &header, true); |
|
dvander@0
|
279 |
} else { |
|
dvander@0
|
280 |
__ jump(&header); |
|
dvander@0
|
281 |
} |
|
dvander@0
|
282 |
|
|
dvander@10
|
283 |
__ bind(&join); |
|
dvander@10
|
284 |
|
|
dvander@1
|
285 |
leaveScope(node->scope()); |
|
dvander@0
|
286 |
assert(__ stackDepth() == 0); |
|
dvander@0
|
287 |
} |
|
dvander@0
|
288 |
|
|
dvander@0
|
289 |
void |
|
dvander@9
|
290 |
BytecodeCompiler::visit(WhileStatement *node) |
|
dvander@9
|
291 |
{ |
|
dvander@10
|
292 |
Label header, join; |
|
dvander@9
|
293 |
|
|
dvander@9
|
294 |
__ bind(&header); |
|
dvander@9
|
295 |
|
|
dvander@10
|
296 |
LoopScope loop(scope_, &join, &header, &loop_); |
|
dvander@10
|
297 |
|
|
dvander@9
|
298 |
if (node->token() == TOK_WHILE) { |
|
dvander@9
|
299 |
visitForTest(node->condition(), &join, false); |
|
dvander@9
|
300 |
node->body()->accept(this); |
|
dvander@9
|
301 |
__ jump(&header); |
|
dvander@9
|
302 |
} else { |
|
dvander@9
|
303 |
node->body()->accept(this); |
|
dvander@9
|
304 |
visitForTest(node->condition(), &header, true); |
|
dvander@9
|
305 |
} |
|
dvander@10
|
306 |
|
|
dvander@10
|
307 |
__ bind(&join); |
|
dvander@10
|
308 |
} |
|
dvander@10
|
309 |
|
|
dvander@10
|
310 |
void |
|
dvander@10
|
311 |
BytecodeCompiler::visit(BreakStatement *node) |
|
dvander@10
|
312 |
{ |
|
dvander@10
|
313 |
unwindTo(loop_->scope()); |
|
dvander@10
|
314 |
__ jump(loop_->break_()); |
|
dvander@10
|
315 |
} |
|
dvander@10
|
316 |
|
|
dvander@10
|
317 |
void |
|
dvander@10
|
318 |
BytecodeCompiler::visit(ContinueStatement *node) |
|
dvander@10
|
319 |
{ |
|
dvander@10
|
320 |
unwindTo(loop_->scope()); |
|
dvander@10
|
321 |
__ jump(loop_->continue_()); |
|
dvander@9
|
322 |
} |
|
dvander@9
|
323 |
|
|
dvander@9
|
324 |
void |
|
dvander@0
|
325 |
BytecodeCompiler::visit(BlockStatement *node) |
|
dvander@0
|
326 |
{ |
|
dvander@1
|
327 |
AutoEnterScope blockScope(this, node->scope()); |
|
dvander@1
|
328 |
|
|
dvander@0
|
329 |
for (size_t i = 0; i < node->statements()->length(); i++) { |
|
dvander@0
|
330 |
Statement *statement = node->statements()->at(i); |
|
dvander@0
|
331 |
statement->accept(this); |
|
dvander@0
|
332 |
assert(__ stackDepth() == 0); |
|
dvander@0
|
333 |
} |
|
dvander@1
|
334 |
|
|
dvander@1
|
335 |
// We don't bother emitting an "unwind" instruction for function scopes, |
|
dvander@1
|
336 |
// since this is taken care of by the calling convention. |
|
dvander@1
|
337 |
if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION) |
|
dvander@1
|
338 |
leaveScope(node->scope()); |
|
dvander@0
|
339 |
} |
|
dvander@0
|
340 |
|
|
dvander@0
|
341 |
void |
|
dvander@4
|
342 |
BytecodeCompiler::visit(IntegerLiteral *node) |
|
dvander@0
|
343 |
{ |
|
dvander@0
|
344 |
__ int_(node->value()); |
|
dvander@0
|
345 |
} |
|
dvander@0
|
346 |
|
|
dvander@0
|
347 |
void |
|
dvander@4
|
348 |
BytecodeCompiler::visit(FloatLiteral *node) |
|
dvander@4
|
349 |
{ |
|
dvander@4
|
350 |
__ float_((float)node->value()); |
|
dvander@4
|
351 |
} |
|
dvander@4
|
352 |
|
|
dvander@4
|
353 |
void |
|
dvander@0
|
354 |
BytecodeCompiler::visit(VariableDeclaration *node) |
|
dvander@0
|
355 |
{ |
|
dvander@0
|
356 |
Variable *var = node->variable(); |
|
dvander@0
|
357 |
assert(var->location() == Variable::STACK); |
|
dvander@0
|
358 |
|
|
dvander@0
|
359 |
Type *type = var->type(); |
|
dvander@0
|
360 |
if (type->isArray()) { |
|
dvander@0
|
361 |
bool isConstant = true; |
|
dvander@0
|
362 |
for (Type *child = type; child->isArray(); child = child->contained()) { |
|
dvander@0
|
363 |
if (child->elements() == Type::UNKNOWN_SIZE) { |
|
dvander@0
|
364 |
isConstant = false; |
|
dvander@0
|
365 |
break; |
|
dvander@0
|
366 |
} |
|
dvander@0
|
367 |
} |
|
dvander@0
|
368 |
|
|
dvander@0
|
369 |
if (!isConstant) { |
|
dvander@0
|
370 |
for (size_t i = 0; i < node->postDimensions()->size(); i++) { |
|
dvander@0
|
371 |
Expression *expr = node->postDimensions()->at(i); |
|
dvander@0
|
372 |
expr->accept(this); |
|
dvander@0
|
373 |
} |
|
dvander@0
|
374 |
} |
|
dvander@0
|
375 |
|
|
dvander@0
|
376 |
__ stackarray(type); |
|
dvander@0
|
377 |
} else { |
|
dvander@0
|
378 |
if (node->initialization()) { |
|
dvander@0
|
379 |
node->initialization()->accept(this); |
|
dvander@0
|
380 |
} else { |
|
dvander@0
|
381 |
if (!node->postDimensions()) |
|
dvander@0
|
382 |
__ int_(0); |
|
dvander@0
|
383 |
} |
|
dvander@0
|
384 |
} |
|
dvander@0
|
385 |
__ setlocal(var->slot()); |
|
dvander@0
|
386 |
__ pop(); |
|
dvander@0
|
387 |
|
|
dvander@0
|
388 |
locals_[var->slot()] = var->type(); |
|
dvander@0
|
389 |
} |
|
dvander@0
|
390 |
|
|
dvander@0
|
391 |
void |
|
dvander@0
|
392 |
BytecodeCompiler::visit(CallExpression *node) |
|
dvander@0
|
393 |
{ |
|
dvander@0
|
394 |
NameProxy *fun = node->callee()->toNameProxy(); |
|
dvander@0
|
395 |
|
|
dvander@0
|
396 |
for (size_t i = 0; i < node->arguments()->size(); i++) { |
|
dvander@0
|
397 |
Expression *arg = node->arguments()->at(i); |
|
dvander@0
|
398 |
arg->accept(this); |
|
dvander@0
|
399 |
} |
|
dvander@0
|
400 |
|
|
dvander@0
|
401 |
__ callglobal(node->arguments()->size(), 0); |
|
dvander@0
|
402 |
} |
|
dvander@0
|
403 |
|
|
dvander@0
|
404 |
void |
|
dvander@0
|
405 |
BytecodeCompiler::visit(IfStatement *node) |
|
dvander@0
|
406 |
{ |
|
dvander@0
|
407 |
if (!node->ifFalse()) { |
|
dvander@0
|
408 |
Label fail; |
|
dvander@0
|
409 |
visitForTest(node->condition(), &fail, false); |
|
dvander@0
|
410 |
node->ifTrue()->accept(this); |
|
dvander@0
|
411 |
__ bind(&fail); |
|
dvander@0
|
412 |
} else { |
|
dvander@0
|
413 |
Label fail, join; |
|
dvander@0
|
414 |
visitForTest(node->condition(), &fail, false); |
|
dvander@0
|
415 |
node->ifTrue()->accept(this); |
|
dvander@0
|
416 |
__ jump(&join); |
|
dvander@0
|
417 |
__ bind(&fail); |
|
dvander@0
|
418 |
node->ifFalse()->accept(this); |
|
dvander@0
|
419 |
__ bind(&join); |
|
dvander@0
|
420 |
} |
|
dvander@0
|
421 |
} |
|
dvander@0
|
422 |
|
|
dvander@0
|
423 |
void |
|
dvander@0
|
424 |
BytecodeCompiler::visit(FunctionStatement *node) |
|
dvander@0
|
425 |
{ |
|
dvander@0
|
426 |
BytecodeCompiler child(tree_); |
|
dvander@0
|
427 |
Code *code = child.compileFunction(module_, node); |
|
dvander@0
|
428 |
|
|
dvander@0
|
429 |
assert(!module_->getFunction(node->fun()->slot())); |
|
dvander@0
|
430 |
module_->setFunction(node->fun()->slot(), code); |
|
dvander@0
|
431 |
} |
|
dvander@0
|
432 |
|
|
dvander@2
|
433 |
void |
|
dvander@2
|
434 |
BytecodeCompiler::visit(EnumStatement *node) |
|
dvander@2
|
435 |
{ |
|
dvander@2
|
436 |
// :TODO: eventually, we'll export these. |
|
dvander@2
|
437 |
} |
|
dvander@2
|
438 |
|
|
dvander@0
|
439 |
Code * |
|
dvander@0
|
440 |
BytecodeCompiler::compileFunction(Module *module, FunctionStatement *node) |
|
dvander@0
|
441 |
{ |
|
dvander@1
|
442 |
AutoEnterScope functionScope(this, node->scope()); |
|
dvander@1
|
443 |
|
|
dvander@0
|
444 |
locals_ = new Type *[node->scope()->maxContainedLocals()]; |
|
dvander@0
|
445 |
memset(locals_, 0, sizeof(Type *) * node->scope()->maxContainedLocals()); |
|
dvander@0
|
446 |
|
|
dvander@0
|
447 |
node->body()->accept(this); |
|
dvander@0
|
448 |
|
|
dvander@0
|
449 |
__ stop(); |
|
dvander@0
|
450 |
|
|
dvander@0
|
451 |
if (__ oom()) |
|
dvander@0
|
452 |
return false; |
|
dvander@0
|
453 |
|
|
dvander@0
|
454 |
bytecode *start = (bytecode *)malloc(__ length() * sizeof(bytecode)); |
|
dvander@0
|
455 |
memcpy(start, __ buffer(), __ length()); |
|
dvander@0
|
456 |
|
|
dvander@0
|
457 |
unsigned nargs = node->scope()->numArguments(); |
|
dvander@0
|
458 |
Type **args = new Type *[nargs]; |
|
dvander@0
|
459 |
for (size_t i = 0; i < node->scope()->numArguments(); i++) |
|
dvander@0
|
460 |
args[i] = node->scope()->getArgument(i)->type(); |
|
dvander@0
|
461 |
|
|
dvander@0
|
462 |
for (size_t i = 0; i < node->scope()->maxContainedLocals(); i++) |
|
dvander@0
|
463 |
assert(locals_[i]); |
|
dvander@0
|
464 |
|
|
dvander@0
|
465 |
Code *code = new Code(module, |
|
dvander@0
|
466 |
start, |
|
dvander@0
|
467 |
__ length(), |
|
dvander@0
|
468 |
args, |
|
dvander@0
|
469 |
nargs, |
|
dvander@0
|
470 |
locals_, |
|
dvander@0
|
471 |
node->scope()->maxContainedLocals(), |
|
dvander@0
|
472 |
__ maxStackDepth()); |
|
dvander@0
|
473 |
|
|
dvander@0
|
474 |
return code; |
|
dvander@0
|
475 |
} |
|
dvander@0
|
476 |
|
|
dvander@0
|
477 |
Module * |
|
dvander@0
|
478 |
BytecodeCompiler::compile() |
|
dvander@0
|
479 |
{ |
|
dvander@0
|
480 |
Code **functions = new Code *[tree_->scope()->numFunctions()]; |
|
dvander@0
|
481 |
memset(functions, 0, sizeof(Code *) * tree_->scope()->numFunctions()); |
|
dvander@0
|
482 |
|
|
dvander@0
|
483 |
module_ = new Module(functions, tree_->scope()->numFunctions()); |
|
dvander@0
|
484 |
|
|
dvander@0
|
485 |
for (size_t i = 0; i < tree_->statements()->length(); i++) { |
|
dvander@0
|
486 |
Statement *statement = tree_->statements()->at(i); |
|
dvander@0
|
487 |
statement->accept(this); |
|
dvander@0
|
488 |
} |
|
dvander@0
|
489 |
|
|
dvander@0
|
490 |
#ifndef NDEBUG |
|
dvander@0
|
491 |
for (size_t i = 0; i < tree_->scope()->numFunctions(); i++) |
|
dvander@0
|
492 |
assert(functions[i]); |
|
dvander@0
|
493 |
#endif |
|
dvander@0
|
494 |
|
|
dvander@0
|
495 |
return module_; |
|
dvander@0
|
496 |
} |