Remove 'argc' field of OP_CALLGLOBAL.
1 /* vim: set ts=4 sw=4 tw=99 et:
3 * Copyright (C) 2012 David Anderson
5 * This file is part of JITCraft.
7 * JITCraft is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License as published by the Free
9 * Software Foundation, either version 3 of the License, or (at your option)
12 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with
17 * JITCraft. If not, see http://www.gnu.org/licenses/.
19 #ifndef _include_bytecode_emitter_h_
20 #define _include_bytecode_emitter_h_
26 #include "NameBinding.h"
34 typedef std::vector<ScopedRoot<Object> *> ObjectList;
39 bytecode *buffer_pos_;
40 bytecode *buffer_end_;
41 bytecode inline_buffer_[512];
43 unsigned maxStackDepth_;
48 static const size_t MAX_LENGTH = INT_MAX / 2;
51 bool growBuffer(size_t bytes);
53 // Checking the return value is not necessary, since the inline buffer is
55 bool ensure(size_t bytes) {
56 if (buffer_pos_ + bytes > buffer_end_)
57 return growBuffer(bytes);
61 void writeUint8(unsigned value) {
62 assert(value >= 0 && value <= UCHAR_MAX);
63 *buffer_pos_++ = value;
65 void writeFloat(float value) {
66 *(float *)buffer_pos_ = value;
67 buffer_pos_ += sizeof(float);
69 void writeInt32(int value) {
70 *(int *)buffer_pos_ = value;
71 buffer_pos_ += sizeof(int);
73 void writeUint32(unsigned value) {
74 *(unsigned *)buffer_pos_ = value;
75 buffer_pos_ += sizeof(unsigned);
77 void writeOp(Opcode op) {
79 stackDepth_ += OpcodeInfo[op].ndefs;
80 if (OpcodeInfo[op].nuses != -1)
81 stackDepth_ -= OpcodeInfo[op].nuses;
82 if (stackDepth_ > maxStackDepth_)
83 maxStackDepth_ = stackDepth_;
85 void writeObject(Object *obj) {
86 writeUint32(objects_.size());
87 ScopedRoot<Object> *root = new ScopedRoot<Object>(obj);
90 objects_.push_back(root);
93 int position() const {
94 assert(buffer_pos_ - buffer_ < INT_MAX / 2);
95 return int(buffer_pos_ - buffer_);
101 bytecode *buffer() const {
104 unsigned length() const {
105 return unsigned(buffer_pos_ - buffer_);
110 unsigned stackDepth() const {
113 unsigned maxStackDepth() const {
114 return maxStackDepth_;
116 const ObjectList *objects() const {
120 void drop(unsigned amt) {
121 assert(amt <= stackDepth_);
126 // A label represents a local control-flow target in the bytecode. A label
127 // may be in three states:
129 // (1) Empty - the label is not used yet.
130 // (2) Pending - the label has incoming jumps, but the actual location of
131 // is not yet known. The list of jumps is threaded through
132 // the four bytes reserved for each emitted jump target. In
133 // this case, the offset field is the location of the most
134 // recently emitted incoming jump.
135 // (3) Bound - the label's position has been pinned.
137 // A jump can be emitted to a label in any state. Binding a label
138 // immediately backpatches all pending incoming jumps. A label must be
139 // bound if it is used.
145 void setOffset(int offset) {
147 assert(offset_ == offset);
151 static const int INVALID_OFFSET = -1;
155 : offset_(INVALID_OFFSET),
161 assert(bound_ || offset_ == INVALID_OFFSET);
170 void bind(int offset) {
175 int link(int offset) {
184 int patchJumpAt(int at, int to) {
185 assert(at >= 0 && at < position());
186 int old = *(int *)(buffer_ + at + 1);
187 *(int *)(buffer_ + at + 1) = (to - at);
191 void singleByteOp(Opcode op) {
192 assert(OpcodeInfo[op].length == 1);
193 ensure(OpcodeInfo[op].length);
198 void int_(int value) {
207 void getlocal(unsigned local) {
208 ensure(OP_GETLOCAL_LENGTH);
209 writeOp(OP_GETLOCAL);
212 void setlocal(unsigned local) {
213 ensure(OP_SETLOCAL_LENGTH);
214 writeOp(OP_SETLOCAL);
217 void getarg(unsigned slot) {
218 ensure(OP_GETARG_LENGTH);
222 void setarg(unsigned slot) {
223 ensure(OP_SETARG_LENGTH);
228 void j(Opcode op, Label *label) {
229 // Since jumps can skip around the stream, do not try to do anything
230 // in a potentially truncated state.
234 assert(op >= OP_JL && op <= OP_JUMP);
235 ensure(OP_JUMP_LENGTH);
237 if (label->bound()) {
238 // We can immediately emit this jump.
239 int distance = label->offset() - position();
241 writeInt32(distance);
243 // We can't emit this jump yet. Add a placeholder.
244 int old = label->link(position());
249 void bind(Label *label) {
253 assert(!label->bound());
255 int offset = label->offset();
256 while (offset != Label::INVALID_OFFSET)
257 offset = patchJumpAt(offset, position());
259 label->bind(position());
261 void jump(Label *label) {
265 void binary(Opcode op) {
270 singleByteOp(OP_POP);
273 singleByteOp(OP_STOP);
275 void callglobal(unsigned index) {
276 ensure(OP_CALLGLOBAL_LENGTH);
277 writeOp(OP_CALLGLOBAL);
280 void getarray(PrimitiveType type) {
282 case PrimitiveType_Float:
283 singleByteOp(OP_GETARRAY_F);
285 case PrimitiveType_Int32:
286 singleByteOp(OP_GETARRAY_I);
289 assert(type == PrimitiveType_Char);
290 singleByteOp(OP_GETARRAY_C);
294 void setarray(PrimitiveType type) {
296 case PrimitiveType_Float:
297 singleByteOp(OP_SETARRAY_F);
299 case PrimitiveType_Int32:
300 singleByteOp(OP_SETARRAY_I);
303 assert(type == PrimitiveType_Char);
304 singleByteOp(OP_SETARRAY_C);
309 singleByteOp(OP_GETARRAY_O);
312 singleByteOp(OP_BOUNDS);
314 void float_(float value) {
315 ensure(OP_FLOAT_LENGTH);
320 singleByteOp(OP_CVT_I2F);
322 void newarray_lifo(Handle<Map> map) {
323 ensure(OP_NEWARRAY_LIFO_LENGTH);
324 writeOp(OP_NEWARRAY_LIFO);
327 void savelifo(unsigned slot) {
328 ensure(OP_SAVELIFO_LENGTH);
329 writeOp(OP_SAVELIFO);
332 void unwindlifo(unsigned slot) {
333 ensure(OP_UNWINDLIFO_LENGTH);
334 writeOp(OP_UNWINDLIFO);
337 void newref(Variable *var) {
338 if (var->location() == Variable::STACK) {
339 ensure(OP_VARREF_LIFO_LENGTH);
340 writeOp(OP_VARREF_LIFO);
342 assert(var->location() == Variable::PARAMETER);
343 ensure(OP_ARGREF_LIFO_LENGTH);
344 writeOp(OP_ARGREF_LIFO);
346 writeUint32(var->slot());
348 void get(Variable *var) {
349 if (var->location() == Variable::STACK) {
350 getlocal(var->slot());
352 assert(var->location() == Variable::PARAMETER);
356 void set(Variable *var) {
357 assert(!var->type()->isReference());
358 if (var->location() == Variable::STACK) {
359 setlocal(var->slot());
361 assert(var->location() == Variable::PARAMETER);
365 void slotref_lifo() {
366 singleByteOp(OP_SLOTREF_LIFO);
368 void arrayref_lifo() {
369 singleByteOp(OP_ARRAYREF_LIFO);
371 void getref(PrimitiveType type) {
372 if (type == PrimitiveType_Int32) {
373 singleByteOp(OP_GETREF_I);
375 assert(type == PrimitiveType_Float);
376 singleByteOp(OP_GETREF_F);
379 void setref(PrimitiveType type) {
380 if (type == PrimitiveType_Int32) {
381 singleByteOp(OP_SETREF_I);
383 assert(type == PrimitiveType_Float);
384 singleByteOp(OP_SETREF_F);
387 void object(Handle<Object> obj) {
388 ensure(OP_OBJECT_LENGTH);
393 singleByteOp(OP_ARRAYCOPY);
396 singleByteOp(OP_DUP);
399 singleByteOp(OP_DUP2);
402 singleByteOp(OP_SWAP);
405 singleByteOp(OP_ROLL3);
408 singleByteOp(OP_PICK2);
411 singleByteOp(OP_PICK3);
417 #endif // _include_bytecode_emitter_h_