Initial import of prototype.
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 writeInt32(int value) {
58 *(int *)buffer_pos_ = value;
59 buffer_pos_ += sizeof(int);
61 void writeUint32(unsigned value) {
62 *(unsigned *)buffer_pos_ = value;
63 buffer_pos_ += sizeof(unsigned);
65 void writeOp(Opcode op) {
67 stackDepth_ += OpcodeInfo[op].ndefs;
68 if (OpcodeInfo[op].nuses != -1)
69 stackDepth_ -= OpcodeInfo[op].nuses;
70 if (stackDepth_ > maxStackDepth_)
71 maxStackDepth_ = stackDepth_;
74 int position() const {
75 assert(buffer_pos_ - buffer_ < INT_MAX / 2);
76 return int(buffer_pos_ - buffer_);
82 bytecode *buffer() const {
85 unsigned length() const {
86 return unsigned(buffer_pos_ - buffer_);
91 unsigned stackDepth() const {
94 unsigned maxStackDepth() const {
95 return maxStackDepth_;
99 // A label represents a local control-flow target in the bytecode. A label
100 // may be in three states:
102 // (1) Empty - the label is not used yet.
103 // (2) Pending - the label has incoming jumps, but the actual location of
104 // is not yet known. The list of jumps is threaded through
105 // the four bytes reserved for each emitted jump target. In
106 // this case, the offset field is the location of the most
107 // recently emitted incoming jump.
108 // (3) Bound - the label's position has been pinned.
110 // A jump can be emitted to a label in any state. Binding a label
111 // immediately backpatches all pending incoming jumps. A label must be
112 // bound if it is used.
118 void setOffset(int offset) {
120 assert(offset_ == offset);
124 static const int INVALID_OFFSET = -1;
128 : offset_(INVALID_OFFSET),
134 assert(bound_ || offset_ == INVALID_OFFSET);
143 void bind(int offset) {
148 int link(int offset) {
157 int patchJumpAt(int at, int to) {
158 assert(at >= 0 && at < position());
159 int old = *(int *)(buffer_ + at + 1);
160 *(int *)(buffer_ + at + 1) = (to - at);
164 void singleByteOp(Opcode op) {
165 assert(OpcodeInfo[op].length == 1);
166 ensure(OpcodeInfo[op].length);
171 void int_(int value) {
180 void getlocal(unsigned local) {
181 ensure(OP_GETLOCAL_LENGTH);
182 writeOp(OP_GETLOCAL);
185 void setlocal(unsigned local) {
186 ensure(OP_SETLOCAL_LENGTH);
187 writeOp(OP_SETLOCAL);
190 void getarg(unsigned slot) {
191 ensure(OP_GETARG_LENGTH);
195 void setarg(unsigned slot) {
196 ensure(OP_SETARG_LENGTH);
201 void j(Opcode op, Label *label) {
202 // Since jumps can skip around the stream, do not try to do anything
203 // in a potentially truncated state.
207 assert(op >= OP_JL && op <= OP_JUMP);
208 ensure(OP_JUMP_LENGTH);
210 if (label->bound()) {
211 // We can immediately emit this jump.
212 int distance = label->offset() - position();
214 writeInt32(distance);
216 // We can't emit this jump yet. Add a placeholder.
217 int old = label->link(position());
222 void bind(Label *label) {
226 assert(!label->bound());
228 int offset = label->offset();
229 while (offset != Label::INVALID_OFFSET)
230 offset = patchJumpAt(offset, position());
232 label->bind(position());
234 void jump(Label *label) {
238 void binary(Opcode op) {
243 singleByteOp(OP_POP);
246 singleByteOp(OP_STOP);
248 void callglobal(unsigned nargs, unsigned index) {
249 ensure(OP_CALLGLOBAL_LENGTH);
250 writeOp(OP_CALLGLOBAL);
254 stackDepth_ -= nargs;
257 singleByteOp(OP_LD_STA_I);
260 singleByteOp(OP_ST_STA_I);
263 singleByteOp(OP_LD_STA_P);
265 void stackarray(Type *type);
267 singleByteOp(OP_BOUNDS_STA);
273 #endif // _include_bytecode_emitter_h_