Normalise line endings.
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_
24 #include "../Opcodes.h"
25 #include "../Handles.h"
26 #include "../CompactBuffer.h"
28 #include "../HashTable.h"
29 #include "../VirtualObjectVisitor.h"
33 // An overarching note on overflows: Though we should use CheckedInt, we rely
34 // on a source-length cap covering all possible overflow checks. As long as
35 // the source length is capped to INT_MAX, the number of AST nodes will be
36 // strictly beneath that cap, and so to will most things generated by the
37 // AST. For example, local and argument counts, number of functions, fields
38 // in a struct, et cetera. Not everything can be covered by this cap: the
39 // stack depth, number of bytecodes for example. In these cases we explicitly
40 // test for overflow of INT_MAX and in other cases we assert.
42 // In the future, we should of course use a checked int wrapper.
56 OopRecord(unsigned length, unsigned offset)
76 Entry(String *string, unsigned index)
85 typedef Entry Payload;
87 static uint32 hash(String *string) {
88 return HashPointer(string);
91 static bool matches(String *key, Entry &e) {
92 return key == e.string;
96 typedef HashTable<Policy, ZoneAllocatorPolicy> Set;
101 void accept(VirtualObjectVisitor *visitor);
103 bool add(Handle<String> name, unsigned *indexp);
104 size_t stringCount() const {
105 return strings_.length();
107 String *stringAt(size_t i) const {
108 return strings_[i].string;
113 Vector<Entry> strings_;
117 // The bytecode emitter assists in building Code objects, by emitting opcodes
118 // and tracking stack information. Since the SemA creates temporary pool/root
119 // scopes, we cannot use ScopedRoot or PoolObjects. Instead, BCE gets a
120 // special marking function.
121 class BytecodeEmitter : public AutoRooted
125 bytecode *buffer_pos_;
126 bytecode *buffer_end_;
127 bytecode inline_buffer_[512];
129 unsigned maxStackDepth_;
130 Vector<bool> oopMap_;
131 Vector<OopRecord *> oopRecords_;
132 CompactBufferWriter sourcemap_;
133 unsigned lastCodePosition_;
135 StringTable strings_;
136 Vector<Symbol *> locals_;
137 Vector<Object *> objects_;
139 unsigned maxLoopDepth_;
142 // The maximum size of a code object must be such that the distance between
143 // two instructions fits into a signed, 31-bit integer. This ensures that
144 // all code-bounded buffers (like the number of object literals or
145 // safepoints) does not need to be bounds checked. It also means we can add
146 // any two offsets and be guaranteed that they don't overflow.
147 static const size_t MAX_LENGTH = INT_MAX / 2;
150 bool growBuffer(size_t bytes);
152 // Checking the return value is not necessary, since the inline buffer is
153 // used as a ballast.
154 bool ensure(size_t bytes) {
155 if (buffer_pos_ + bytes > buffer_end_)
156 return growBuffer(bytes);
160 void writeUint8(unsigned value) {
161 assert(value <= UCHAR_MAX);
162 *buffer_pos_++ = value;
164 void writeFloat(float value) {
165 *(float *)buffer_pos_ = value;
166 buffer_pos_ += sizeof(float);
168 void writeInt32(int value) {
169 *(int *)buffer_pos_ = value;
170 buffer_pos_ += sizeof(int);
172 void writeUint32(unsigned value) {
173 *(unsigned *)buffer_pos_ = value;
174 buffer_pos_ += sizeof(unsigned);
176 void writeOp(Opcode op) {
181 for (int i = 0; i < OpcodeInfo[op].nuses; i++)
183 for (int i = 0; i < OpcodeInfo[op].ndefs; i++)
184 oopMap_.append(false);
185 if (oopMap_.length() > maxStackDepth_)
186 maxStackDepth_ = oopMap_.length();
188 void writeObject(Object *obj) {
191 writeUint32(objects_.length());
192 if (!objects_.append(obj))
196 int position() const {
197 assert(buffer_pos_ - buffer_ < INT_MAX / 2);
198 return int(buffer_pos_ - buffer_);
205 void accept(VirtualObjectVisitor *visitor);
207 bytecode *buffer() const {
210 unsigned length() const {
211 return unsigned(buffer_pos_ - buffer_);
214 return oom_ || sourcemap_.oom();
216 unsigned stackDepth() const {
217 return oopMap_.length();
219 unsigned maxStackDepth() const {
220 return maxStackDepth_;
223 void drop(unsigned amt) {
224 assert(amt <= stackDepth());
225 for (unsigned i = 0; i < amt; i++)
229 void note_position(const SourcePosition &pos);
230 void setFirstLine(unsigned line) {
231 assert(!sourcemap_.length());
236 // A label represents a local control-flow target in the bytecode. A label
237 // may be in three states:
239 // (1) Empty - the label is not used yet.
240 // (2) Pending - the label has incoming jumps, but the actual location of
241 // is not yet known. The list of jumps is threaded through
242 // the four bytes reserved for each emitted jump target. In
243 // this case, the offset field is the location of the most
244 // recently emitted incoming jump.
245 // (3) Bound - the label's position has been pinned.
247 // A jump can be emitted to a label in any state. Binding a label
248 // immediately backpatches all pending incoming jumps. A label must be
249 // bound if it is used.
255 void setOffset(int offset) {
257 assert(offset_ == offset);
261 static const int INVALID_OFFSET = -1;
265 : offset_(INVALID_OFFSET),
271 assert(bound_ || offset_ == INVALID_OFFSET);
280 void bind(int offset) {
285 int link(int offset) {
294 int patchJumpAt(int at, int to) {
295 assert(at >= 0 && at < position());
296 int old = *(int *)(buffer_ + at + 1);
297 *(int *)(buffer_ + at + 1) = (to - at);
301 void singleByteOp(Opcode op) {
302 assert(OpcodeInfo[op].length == 1);
303 ensure(OpcodeInfo[op].length);
307 // Mark a stack slot as having an object pointer.
308 void markOop(unsigned depth, bool oop = true) {
311 oopMap_[oopMap_.length() - depth] = oop;
313 bool getOop(unsigned depth) {
316 return oopMap_[oopMap_.length() - depth];
319 // Mark the current bytecode position as either re-entrant (meaning, it
320 // can leave the interpreter or call to another function), or causing GC.
321 // This will record which stack slots have objects and associate that
322 // information with the current pc.
326 void int_(int value) {
335 void getlocal(VariableSymbol *var);
336 void setlocal(VariableSymbol *var);
337 void getarg(VariableSymbol *var);
338 void setarg(VariableSymbol *var);
340 void j(Opcode op, Label *label) {
341 // Since jumps can skip around the stream, do not try to do anything
342 // in a potentially truncated state.
346 assert(op == OP_JT || op == OP_JF || op == OP_JUMP ||
347 op == OP_CONTINUE || op == OP_BREAK);
348 ensure(OP_JUMP_LENGTH);
350 if (label->bound()) {
351 // We can immediately emit this jump.
352 int distance = label->offset() - position();
354 writeInt32(distance);
356 // We can't emit this jump yet. Add a placeholder.
357 int old = label->link(position());
362 void bind(Label *label) {
366 assert(!label->bound());
368 int offset = label->offset();
369 while (offset != Label::INVALID_OFFSET)
370 offset = patchJumpAt(offset, position());
372 label->bind(position());
374 void jump(Label *label) {
378 void binary(Opcode op) {
381 void unary(Opcode op) {
386 singleByteOp(OP_POP);
389 singleByteOp(OP_STOP);
391 void call(Handle<FunctionType> fun, unsigned argc) {
394 if (fun->isNative()) {
395 ensure(OP_CALLNATIVE_LENGTH);
396 writeOp(OP_CALLNATIVE);
400 ensure(OP_CALL_LENGTH);
404 if (fun->returnType()->isVoid())
406 else if (fun->returnType()->isTraceable())
411 void getelem(Type *type) {
412 singleByteOp(OP_GETELEM);
414 if (type->isTraceable())
417 void setelem(Type *type) {
418 singleByteOp(OP_SETELEM);
421 void getfield(unsigned index, Type *type) {
422 ensure(OP_GETFIELD_LENGTH);
423 writeOp(OP_GETFIELD);
426 if (type->isTraceable())
429 void setfield(unsigned index, Type *type) {
430 ensure(OP_SETFIELD_LENGTH);
431 writeOp(OP_SETFIELD);
434 if (type->isTraceable())
439 int offset = position();
441 ensure(OP_ENTERLOOP);
442 writeOp(OP_ENTERLOOP);
446 if (loopDepth_ > maxLoopDepth_)
447 maxLoopDepth_ = loopDepth_;
452 singleByteOp(OP_LEAVELOOP);
457 void setLoopUsesLifoStack(int pos) {
458 assert(pos >= 0 && pos < position());
459 assert(*(buffer() + pos) == OP_ENTERLOOP);
460 *(buffer() + pos + 1) = 1;
463 void float_(float value) {
464 ensure(OP_FLOAT_LENGTH);
469 singleByteOp(OP_CVT_I2F);
471 void newarray(Opcode op, Handle<ArrayMap> map, Heap::Tenure tenure) {
472 assert(op == OP_NEWFIXED ||
477 ensure(OpcodeInfo[op].length);
482 if (op == OP_NEWSIZED)
483 drop(map->type()->levels());
487 void newstruct(Handle<Map> map, Heap::Tenure tenure) {
489 ensure(OP_NEWSTRUCT_LENGTH);
490 writeOp(OP_NEWSTRUCT);
495 void deparray(ArrayMap *map) {
497 ensure(OP_DEPARRAY_LENGTH);
498 writeOp(OP_DEPARRAY);
502 void savelifo(unsigned slot) {
503 ensure(OP_SAVELIFO_LENGTH);
504 writeOp(OP_SAVELIFO);
507 void unwindlifo(unsigned slot) {
508 ensure(OP_UNWINDLIFO_LENGTH);
509 writeOp(OP_UNWINDLIFO);
513 void newref(VariableSymbol *var);
515 void slotref_lifo() {
517 singleByteOp(OP_SLOTREF_LIFO);
520 void getref(Type *type) {
521 if (type->pod() == PrimitiveType_Int32) {
522 singleByteOp(OP_GETREF_I);
524 assert(type->pod() == PrimitiveType_Float);
525 singleByteOp(OP_GETREF_F);
528 void setref(Type *type) {
529 if (type->pod() == PrimitiveType_Int32) {
530 singleByteOp(OP_SETREF_I);
532 assert(type->pod() == PrimitiveType_Float);
533 singleByteOp(OP_SETREF_F);
536 void object(Handle<Object> obj) {
539 ensure(OP_OBJECT_LENGTH);
545 singleByteOp(OP_DUPARRAY);
549 singleByteOp(OP_COPYARRAY);
553 singleByteOp(OP_COPYSTRUCT);
557 singleByteOp(OP_SIZEOF);
561 bool oop = getOop(1);
562 singleByteOp(OP_DUP);
566 bool oop2 = getOop(2);
567 bool oop1 = getOop(1);
569 singleByteOp(OP_DUP2);
575 bool oop2 = getOop(2);
576 bool oop1 = getOop(1);
578 singleByteOp(OP_SWAP);
584 bool oop3 = getOop(3);
585 bool oop2 = getOop(2);
586 bool oop1 = getOop(1);
588 singleByteOp(OP_ROLL3);
595 bool oop2 = getOop(2);
596 bool oop1 = getOop(1);
598 singleByteOp(OP_PICK2);
605 bool oop3 = getOop(3);
606 bool oop2 = getOop(2);
607 bool oop1 = getOop(1);
609 singleByteOp(OP_PICK3);
618 singleByteOp(OP_RETURNVOID);
621 singleByteOp(OP_BITNOT);
624 singleByteOp(OP_NOT);
627 singleByteOp(OP_NOT_F);
630 singleByteOp(OP_NEG);
633 singleByteOp(OP_NEG_F);
636 singleByteOp(OP_TRUE);
639 singleByteOp(OP_FALSE);
642 unsigned addString(Handle<String> name) {
644 if (!strings_.add(name, &index)) {
651 void getglobal(Symbol *sym);
652 void setglobal(Symbol *sym);
656 singleByteOp(OP_PUBLIC);
659 void bitcast(Type *type) {
660 ensure(OP_BITCAST_LENGTH);
665 void tableswitch(int low, int high, Label *def, Label **labels) {
666 unsigned tablesize = TableSwitchEntries(low, high);
667 assert(tablesize <= MAX_TABLESWITCH_ENTRIES);
669 ensure(OP_TABLESWITCH_LENGTH);
670 writeOp(OP_TABLESWITCH);
675 // When labels are patched, we assume each position is a jump. Rather
676 // than hack position offsets to make labels work without actual
677 // incoming jumps, we emit a jump inline.
678 for (unsigned i = 0; i < tablesize; i++)
682 void import(unsigned index) {
683 ensure(OP_IMPORT_LENGTH);
689 bool allocate(VariableSymbol *sym);
695 void get(Variable *var) {
696 if (var->location() == Variable::STACK) {
699 assert(var->location() == Variable::PARAMETER);
703 void set(Variable *var) {
704 assert(!var->type()->isReference());
705 if (var->location() == Variable::STACK) {
708 assert(var->location() == Variable::PARAMETER);
717 #endif // _include_bytecode_emitter_h_