Add support for float variables and basic math.
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_
32 bytecode *buffer_pos_;
33 bytecode *buffer_end_;
34 bytecode inline_buffer_[512];
36 unsigned maxStackDepth_;
40 static const size_t MAX_LENGTH = INT_MAX / 2;
43 bool growBuffer(size_t bytes);
45 // Checking the return value is not necessary, since the inline buffer is
47 bool ensure(size_t bytes) {
48 if (buffer_pos_ + bytes > buffer_end_)
49 return growBuffer(bytes);
53 void writeUint8(unsigned value) {
54 assert(value >= 0 && value <= UCHAR_MAX);
55 *buffer_pos_++ = value;
57 void writeFloat(float value) {
58 *(float *)buffer_pos_ = value;
59 buffer_pos_ += sizeof(float);
61 void writeInt32(int value) {
62 *(int *)buffer_pos_ = value;
63 buffer_pos_ += sizeof(int);
65 void writeUint32(unsigned value) {
66 *(unsigned *)buffer_pos_ = value;
67 buffer_pos_ += sizeof(unsigned);
69 void writeOp(Opcode op) {
71 stackDepth_ += OpcodeInfo[op].ndefs;
72 if (OpcodeInfo[op].nuses != -1)
73 stackDepth_ -= OpcodeInfo[op].nuses;
74 if (stackDepth_ > maxStackDepth_)
75 maxStackDepth_ = stackDepth_;
78 int position() const {
79 assert(buffer_pos_ - buffer_ < INT_MAX / 2);
80 return int(buffer_pos_ - buffer_);
86 bytecode *buffer() const {
89 unsigned length() const {
90 return unsigned(buffer_pos_ - buffer_);
95 unsigned stackDepth() const {
98 unsigned maxStackDepth() const {
99 return maxStackDepth_;
103 // A label represents a local control-flow target in the bytecode. A label
104 // may be in three states:
106 // (1) Empty - the label is not used yet.
107 // (2) Pending - the label has incoming jumps, but the actual location of
108 // is not yet known. The list of jumps is threaded through
109 // the four bytes reserved for each emitted jump target. In
110 // this case, the offset field is the location of the most
111 // recently emitted incoming jump.
112 // (3) Bound - the label's position has been pinned.
114 // A jump can be emitted to a label in any state. Binding a label
115 // immediately backpatches all pending incoming jumps. A label must be
116 // bound if it is used.
122 void setOffset(int offset) {
124 assert(offset_ == offset);
128 static const int INVALID_OFFSET = -1;
132 : offset_(INVALID_OFFSET),
138 assert(bound_ || offset_ == INVALID_OFFSET);
147 void bind(int offset) {
152 int link(int offset) {
161 int patchJumpAt(int at, int to) {
162 assert(at >= 0 && at < position());
163 int old = *(int *)(buffer_ + at + 1);
164 *(int *)(buffer_ + at + 1) = (to - at);
168 void singleByteOp(Opcode op) {
169 assert(OpcodeInfo[op].length == 1);
170 ensure(OpcodeInfo[op].length);
175 void int_(int value) {
184 void getlocal(unsigned local) {
185 ensure(OP_GETLOCAL_LENGTH);
186 writeOp(OP_GETLOCAL);
189 void setlocal(unsigned local) {
190 ensure(OP_SETLOCAL_LENGTH);
191 writeOp(OP_SETLOCAL);
194 void getarg(unsigned slot) {
195 ensure(OP_GETARG_LENGTH);
199 void setarg(unsigned slot) {
200 ensure(OP_SETARG_LENGTH);
205 void j(Opcode op, Label *label) {
206 // Since jumps can skip around the stream, do not try to do anything
207 // in a potentially truncated state.
211 assert(op >= OP_JL && op <= OP_JUMP);
212 ensure(OP_JUMP_LENGTH);
214 if (label->bound()) {
215 // We can immediately emit this jump.
216 int distance = label->offset() - position();
218 writeInt32(distance);
220 // We can't emit this jump yet. Add a placeholder.
221 int old = label->link(position());
226 void bind(Label *label) {
230 assert(!label->bound());
232 int offset = label->offset();
233 while (offset != Label::INVALID_OFFSET)
234 offset = patchJumpAt(offset, position());
236 label->bind(position());
238 void jump(Label *label) {
242 void binary(Opcode op) {
247 singleByteOp(OP_POP);
250 singleByteOp(OP_STOP);
252 void callglobal(unsigned nargs, unsigned index) {
253 ensure(OP_CALLGLOBAL_LENGTH);
254 writeOp(OP_CALLGLOBAL);
258 stackDepth_ -= nargs;
261 singleByteOp(OP_LD_STA_I);
264 singleByteOp(OP_ST_STA_I);
267 singleByteOp(OP_LD_STA_P);
269 void stackarray(Type *type);
270 void unwind(unsigned slot) {
271 ensure(OP_UNWIND_LENGTH);
276 singleByteOp(OP_BOUNDS_STA);
278 void float_(float value) {
279 ensure(OP_FLOAT_LENGTH);
284 singleByteOp(OP_CVT_I2F);
290 #endif // _include_bytecode_emitter_h_