Added support for fused math-assign ops (+=, etc).
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 #ifndef _include_bytecode_emitter_h_
19 #define _include_bytecode_emitter_h_
25 #include "NameBinding.h"
35 bytecode *buffer_pos_;
36 bytecode *buffer_end_;
37 bytecode inline_buffer_[512];
39 unsigned maxStackDepth_;
41 std::vector<Object *> objects_;
44 static const size_t MAX_LENGTH = INT_MAX / 2;
47 bool growBuffer(size_t bytes);
49 // Checking the return value is not necessary, since the inline buffer is
51 bool ensure(size_t bytes) {
52 if (buffer_pos_ + bytes > buffer_end_)
53 return growBuffer(bytes);
57 void writeUint8(unsigned value) {
58 assert(value >= 0 && value <= UCHAR_MAX);
59 *buffer_pos_++ = value;
61 void writeFloat(float value) {
62 *(float *)buffer_pos_ = value;
63 buffer_pos_ += sizeof(float);
65 void writeInt32(int value) {
66 *(int *)buffer_pos_ = value;
67 buffer_pos_ += sizeof(int);
69 void writeUint32(unsigned value) {
70 *(unsigned *)buffer_pos_ = value;
71 buffer_pos_ += sizeof(unsigned);
73 void writeOp(Opcode op) {
75 stackDepth_ += OpcodeInfo[op].ndefs;
76 if (OpcodeInfo[op].nuses != -1)
77 stackDepth_ -= OpcodeInfo[op].nuses;
78 if (stackDepth_ > maxStackDepth_)
79 maxStackDepth_ = stackDepth_;
81 void writeObject(Object *obj) {
82 writeUint32(objects_.size());
83 objects_.push_back(obj);
86 int position() const {
87 assert(buffer_pos_ - buffer_ < INT_MAX / 2);
88 return int(buffer_pos_ - buffer_);
94 bytecode *buffer() const {
97 unsigned length() const {
98 return unsigned(buffer_pos_ - buffer_);
103 unsigned stackDepth() const {
106 unsigned maxStackDepth() const {
107 return maxStackDepth_;
109 const std::vector<Object *> *objects() const {
114 // A label represents a local control-flow target in the bytecode. A label
115 // may be in three states:
117 // (1) Empty - the label is not used yet.
118 // (2) Pending - the label has incoming jumps, but the actual location of
119 // is not yet known. The list of jumps is threaded through
120 // the four bytes reserved for each emitted jump target. In
121 // this case, the offset field is the location of the most
122 // recently emitted incoming jump.
123 // (3) Bound - the label's position has been pinned.
125 // A jump can be emitted to a label in any state. Binding a label
126 // immediately backpatches all pending incoming jumps. A label must be
127 // bound if it is used.
133 void setOffset(int offset) {
135 assert(offset_ == offset);
139 static const int INVALID_OFFSET = -1;
143 : offset_(INVALID_OFFSET),
149 assert(bound_ || offset_ == INVALID_OFFSET);
158 void bind(int offset) {
163 int link(int offset) {
172 int patchJumpAt(int at, int to) {
173 assert(at >= 0 && at < position());
174 int old = *(int *)(buffer_ + at + 1);
175 *(int *)(buffer_ + at + 1) = (to - at);
179 void singleByteOp(Opcode op) {
180 assert(OpcodeInfo[op].length == 1);
181 ensure(OpcodeInfo[op].length);
186 void int_(int value) {
195 void getlocal(unsigned local) {
196 ensure(OP_GETLOCAL_LENGTH);
197 writeOp(OP_GETLOCAL);
200 void setlocal(unsigned local) {
201 ensure(OP_SETLOCAL_LENGTH);
202 writeOp(OP_SETLOCAL);
205 void getarg(unsigned slot) {
206 ensure(OP_GETARG_LENGTH);
210 void setarg(unsigned slot) {
211 ensure(OP_SETARG_LENGTH);
216 void j(Opcode op, Label *label) {
217 // Since jumps can skip around the stream, do not try to do anything
218 // in a potentially truncated state.
222 assert(op >= OP_JL && op <= OP_JUMP);
223 ensure(OP_JUMP_LENGTH);
225 if (label->bound()) {
226 // We can immediately emit this jump.
227 int distance = label->offset() - position();
229 writeInt32(distance);
231 // We can't emit this jump yet. Add a placeholder.
232 int old = label->link(position());
237 void bind(Label *label) {
241 assert(!label->bound());
243 int offset = label->offset();
244 while (offset != Label::INVALID_OFFSET)
245 offset = patchJumpAt(offset, position());
247 label->bind(position());
249 void jump(Label *label) {
253 void binary(Opcode op) {
258 singleByteOp(OP_POP);
261 singleByteOp(OP_STOP);
263 void callglobal(unsigned nargs, unsigned index) {
264 ensure(OP_CALLGLOBAL_LENGTH);
265 writeOp(OP_CALLGLOBAL);
269 stackDepth_ -= nargs;
271 void getarray(PrimitiveType type) {
273 case PrimitiveType_Float:
274 singleByteOp(OP_GETARRAY_F);
276 case PrimitiveType_Int32:
277 singleByteOp(OP_GETARRAY_I);
280 assert(type == PrimitiveType_Char);
281 singleByteOp(OP_GETARRAY_C);
285 void setarray(PrimitiveType type) {
287 case PrimitiveType_Float:
288 singleByteOp(OP_SETARRAY_F);
290 case PrimitiveType_Int32:
291 singleByteOp(OP_SETARRAY_I);
294 assert(type == PrimitiveType_Char);
295 singleByteOp(OP_SETARRAY_C);
300 singleByteOp(OP_GETARRAY_O);
303 singleByteOp(OP_BOUNDS);
305 void float_(float value) {
306 ensure(OP_FLOAT_LENGTH);
311 singleByteOp(OP_CVT_I2F);
313 void newarray_lifo(Map *map) {
314 ensure(OP_NEWARRAY_LIFO_LENGTH);
315 writeOp(OP_NEWARRAY_LIFO);
318 void savelifo(unsigned slot) {
319 ensure(OP_SAVELIFO_LENGTH);
320 writeOp(OP_SAVELIFO);
323 void unwindlifo(unsigned slot) {
324 ensure(OP_UNWINDLIFO_LENGTH);
325 writeOp(OP_UNWINDLIFO);
328 void newref(Variable *var) {
329 if (var->location() == Variable::STACK) {
330 ensure(OP_VARREF_LIFO_LENGTH);
331 writeOp(OP_VARREF_LIFO);
333 assert(var->location() == Variable::PARAMETER);
334 ensure(OP_ARGREF_LIFO_LENGTH);
335 writeOp(OP_ARGREF_LIFO);
337 writeUint32(var->slot());
339 void get(Variable *var) {
340 if (var->location() == Variable::STACK) {
341 getlocal(var->slot());
343 assert(var->location() == Variable::PARAMETER);
347 void set(Variable *var) {
348 assert(!var->type()->isReference());
349 if (var->location() == Variable::STACK) {
350 setlocal(var->slot());
352 assert(var->location() == Variable::PARAMETER);
356 void slotref_lifo() {
357 singleByteOp(OP_SLOTREF_LIFO);
359 void arrayref_lifo() {
360 singleByteOp(OP_ARRAYREF_LIFO);
362 void getref(PrimitiveType type) {
363 if (type == PrimitiveType_Int32) {
364 singleByteOp(OP_GETREF_I);
366 assert(type == PrimitiveType_Float);
367 singleByteOp(OP_GETREF_F);
370 void setref(PrimitiveType type) {
371 if (type == PrimitiveType_Int32) {
372 singleByteOp(OP_SETREF_I);
374 assert(type == PrimitiveType_Float);
375 singleByteOp(OP_SETREF_F);
378 void object(Object *obj) {
379 ensure(OP_OBJECT_LENGTH);
384 singleByteOp(OP_ARRAYCOPY);
387 singleByteOp(OP_DUP);
390 singleByteOp(OP_DUP2);
396 #endif // _include_bytecode_emitter_h_