Remove all instances of std::vector.
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_
25 #include "NameBinding.h"
33 typedef PoolList<ScopedRoot<Object> *> ObjectList;
35 struct OopRecord : public PoolObject
41 OopRecord(unsigned length, unsigned offset)
55 bytecode *buffer_pos_;
56 bytecode *buffer_end_;
57 bytecode inline_buffer_[512];
59 unsigned maxStackDepth_;
61 PoolList<bool> oopMap_;
62 PoolList<OopRecord *> oopRecords_;
65 // The maximum size of a code object must be such that the distance between
66 // two instructions fits into a signed, 31-bit integer. This ensures that
67 // all code-bounded buffers (like the number of object literals or
68 // safepoints) does not need to be bounds checked. It also means we can add
69 // any two offsets and be guaranteed that they don't overflow.
70 static const size_t MAX_LENGTH = INT_MAX / 2;
73 bool growBuffer(size_t bytes);
75 // Checking the return value is not necessary, since the inline buffer is
77 bool ensure(size_t bytes) {
78 if (buffer_pos_ + bytes > buffer_end_)
79 return growBuffer(bytes);
83 void writeUint8(unsigned value) {
84 assert(value <= UCHAR_MAX);
85 *buffer_pos_++ = value;
87 void writeFloat(float value) {
88 *(float *)buffer_pos_ = value;
89 buffer_pos_ += sizeof(float);
91 void writeInt32(int value) {
92 *(int *)buffer_pos_ = value;
93 buffer_pos_ += sizeof(int);
95 void writeUint32(unsigned value) {
96 *(unsigned *)buffer_pos_ = value;
97 buffer_pos_ += sizeof(unsigned);
99 void writeOp(Opcode op) {
104 for (int i = 0; i < OpcodeInfo[op].nuses; i++)
106 for (int i = 0; i < OpcodeInfo[op].ndefs; i++)
107 oopMap_.append(false);
108 if (oopMap_.length() > maxStackDepth_)
109 maxStackDepth_ = oopMap_.length();
111 void writeObject(Object *obj) {
112 writeUint32(objects_.length());
113 ScopedRoot<Object> *root = new ScopedRoot<Object>(obj);
116 oom_ &= objects_.append(root);
119 int position() const {
120 assert(buffer_pos_ - buffer_ < INT_MAX / 2);
121 return int(buffer_pos_ - buffer_);
125 BytecodeEmitter(PoolAllocator &pool);
127 bytecode *buffer() const {
130 unsigned length() const {
131 return unsigned(buffer_pos_ - buffer_);
136 unsigned stackDepth() const {
137 return oopMap_.length();
139 unsigned maxStackDepth() const {
140 return maxStackDepth_;
142 const ObjectList *objects() const {
145 PoolList<OopRecord *> *oopRecords() {
149 void drop(unsigned amt) {
150 assert(amt <= stackDepth());
151 for (unsigned i = 0; i < amt; i++)
156 // A label represents a local control-flow target in the bytecode. A label
157 // may be in three states:
159 // (1) Empty - the label is not used yet.
160 // (2) Pending - the label has incoming jumps, but the actual location of
161 // is not yet known. The list of jumps is threaded through
162 // the four bytes reserved for each emitted jump target. In
163 // this case, the offset field is the location of the most
164 // recently emitted incoming jump.
165 // (3) Bound - the label's position has been pinned.
167 // A jump can be emitted to a label in any state. Binding a label
168 // immediately backpatches all pending incoming jumps. A label must be
169 // bound if it is used.
175 void setOffset(int offset) {
177 assert(offset_ == offset);
181 static const int INVALID_OFFSET = -1;
185 : offset_(INVALID_OFFSET),
191 assert(bound_ || offset_ == INVALID_OFFSET);
200 void bind(int offset) {
205 int link(int offset) {
214 int patchJumpAt(int at, int to) {
215 assert(at >= 0 && at < position());
216 int old = *(int *)(buffer_ + at + 1);
217 *(int *)(buffer_ + at + 1) = (to - at);
221 void singleByteOp(Opcode op) {
222 assert(OpcodeInfo[op].length == 1);
223 ensure(OpcodeInfo[op].length);
227 // Mark a stack slot as having an object pointer.
228 void markOop(unsigned depth, bool oop = true) {
231 oopMap_[oopMap_.length() - depth] = oop;
233 bool getOop(unsigned depth) {
236 return oopMap_[oopMap_.length() - depth];
239 // Mark the current bytecode position as either re-entrant (meaning, it
240 // can leave the interpreter or call to another function), or causing GC.
241 // This will record which stack slots have objects and associate that
242 // information with the current pc.
246 void int_(int value) {
255 void getlocal(Variable *var) {
256 ensure(OP_GETLOCAL_LENGTH);
257 writeOp(OP_GETLOCAL);
258 writeUint32(var->slot());
260 if (var->type()->isTraceable())
263 void setlocal(Variable *var) {
264 ensure(OP_SETLOCAL_LENGTH);
265 writeOp(OP_SETLOCAL);
266 writeUint32(var->slot());
268 if (var->type()->isTraceable())
271 void getarg(Variable *var) {
272 ensure(OP_GETARG_LENGTH);
274 writeUint32(var->slot());
276 if (var->type()->isTraceable())
279 void setarg(Variable *var) {
280 ensure(OP_SETARG_LENGTH);
282 writeUint32(var->slot());
284 if (var->type()->isTraceable())
288 void j(Opcode op, Label *label) {
289 // Since jumps can skip around the stream, do not try to do anything
290 // in a potentially truncated state.
294 assert(op >= OP_JL && op <= OP_JUMP);
295 ensure(OP_JUMP_LENGTH);
297 if (label->bound()) {
298 // We can immediately emit this jump.
299 int distance = label->offset() - position();
301 writeInt32(distance);
303 // We can't emit this jump yet. Add a placeholder.
304 int old = label->link(position());
309 void bind(Label *label) {
313 assert(!label->bound());
315 int offset = label->offset();
316 while (offset != Label::INVALID_OFFSET)
317 offset = patchJumpAt(offset, position());
319 label->bind(position());
321 void jump(Label *label) {
325 void binary(Opcode op) {
330 singleByteOp(OP_POP);
333 singleByteOp(OP_STOP);
335 void callglobal(unsigned index) {
337 ensure(OP_CALLGLOBAL_LENGTH);
338 writeOp(OP_CALLGLOBAL);
341 void getarray(PrimitiveType type) {
343 case PrimitiveType_Float:
344 singleByteOp(OP_GETARRAY_F);
346 case PrimitiveType_Int32:
347 singleByteOp(OP_GETARRAY_I);
350 assert(type == PrimitiveType_Char);
351 singleByteOp(OP_GETARRAY_C);
355 void setarray(PrimitiveType type) {
357 case PrimitiveType_Float:
358 singleByteOp(OP_SETARRAY_F);
360 case PrimitiveType_Int32:
361 singleByteOp(OP_SETARRAY_I);
364 assert(type == PrimitiveType_Char);
365 singleByteOp(OP_SETARRAY_C);
370 singleByteOp(OP_GETARRAY_O);
374 singleByteOp(OP_BOUNDS);
377 void float_(float value) {
378 ensure(OP_FLOAT_LENGTH);
383 singleByteOp(OP_CVT_I2F);
385 void newarray_lifo(Handle<Map> map) {
387 ensure(OP_NEWARRAY_LIFO_LENGTH);
388 writeOp(OP_NEWARRAY_LIFO);
392 void savelifo(unsigned slot) {
393 ensure(OP_SAVELIFO_LENGTH);
394 writeOp(OP_SAVELIFO);
397 void unwindlifo(unsigned slot) {
398 ensure(OP_UNWINDLIFO_LENGTH);
399 writeOp(OP_UNWINDLIFO);
402 void newref(Variable *var) {
404 if (var->location() == Variable::STACK) {
405 ensure(OP_VARREF_LIFO_LENGTH);
406 writeOp(OP_VARREF_LIFO);
408 assert(var->location() == Variable::PARAMETER);
409 ensure(OP_ARGREF_LIFO_LENGTH);
410 writeOp(OP_ARGREF_LIFO);
412 writeUint32(var->slot());
416 void slotref_lifo() {
418 singleByteOp(OP_SLOTREF_LIFO);
421 void arrayref_lifo() {
423 singleByteOp(OP_ARRAYREF_LIFO);
426 void getref(PrimitiveType type) {
427 if (type == PrimitiveType_Int32) {
428 singleByteOp(OP_GETREF_I);
430 assert(type == PrimitiveType_Float);
431 singleByteOp(OP_GETREF_F);
434 void setref(PrimitiveType type) {
435 if (type == PrimitiveType_Int32) {
436 singleByteOp(OP_SETREF_I);
438 assert(type == PrimitiveType_Float);
439 singleByteOp(OP_SETREF_F);
442 void object(Handle<Object> obj) {
443 ensure(OP_OBJECT_LENGTH);
449 singleByteOp(OP_ARRAYCOPY);
454 bool oop = getOop(1);
455 singleByteOp(OP_DUP);
459 bool oop2 = getOop(2);
460 bool oop1 = getOop(1);
462 singleByteOp(OP_DUP2);
468 bool oop2 = getOop(2);
469 bool oop1 = getOop(1);
471 singleByteOp(OP_SWAP);
477 bool oop3 = getOop(3);
478 bool oop2 = getOop(2);
479 bool oop1 = getOop(1);
481 singleByteOp(OP_ROLL3);
488 bool oop2 = getOop(2);
489 bool oop1 = getOop(1);
491 singleByteOp(OP_PICK2);
498 bool oop3 = getOop(3);
499 bool oop2 = getOop(2);
500 bool oop1 = getOop(1);
502 singleByteOp(OP_PICK3);
511 void get(Variable *var) {
512 if (var->location() == Variable::STACK) {
515 assert(var->location() == Variable::PARAMETER);
519 void set(Variable *var) {
520 assert(!var->type()->isReference());
521 if (var->location() == Variable::STACK) {
524 assert(var->location() == Variable::PARAMETER);
532 #endif // _include_bytecode_emitter_h_