src/compiler/BytecodeEmitter.h
author David Anderson <dvander@alliedmods.net>
Mon Nov 19 01:13:44 2012 -0800 (2012-11-19)
changeset 220 5df4a112967d
parent 195 c1ba166f3fc4
child 222 0cde1379b29f
permissions -rw-r--r--
Re-added parameter support.
     1 /* vim: set ts=4 sw=4 tw=99 et:
     2  *
     3  * Copyright (C) 2012 David Anderson
     4  *
     5  * This file is part of JITCraft.
     6  *
     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)
    10  * any later version.
    11  * 
    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.
    15  *
    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/.
    18  */
    19 #ifndef _include_bytecode_emitter_h_
    20 #define _include_bytecode_emitter_h_
    21 
    22 #include <assert.h>
    23 #include <limits.h>
    24 #include "../Opcodes.h"
    25 #include "../Handles.h"
    26 #include "../CompactBuffer.h"
    27 #include "../Array.h"
    28 #include "../HashTable.h"
    29 #include "../VirtualObjectVisitor.h"
    30 
    31 namespace ke {
    32 
    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.
    41 //
    42 // In the future, we should of course use a checked int wrapper.
    43 
    44 class Type;
    45 class Map;
    46 class ArrayMap;
    47 class Symbol;
    48 class VariableSymbol;
    49 
    50 struct OopRecord
    51 {
    52     unsigned depth;
    53     unsigned offset;
    54     Vector<bool> slots;
    55 
    56     OopRecord(unsigned length, unsigned offset)
    57       : depth(length),
    58         offset(offset)
    59     {
    60     }
    61 };
    62 
    63 class StringTable
    64 {
    65     struct Entry
    66     {
    67         String *string;
    68         unsigned index;
    69 
    70         Entry()
    71           : string(NULL),
    72             index(0)
    73         {
    74         }
    75 
    76         Entry(String *string, unsigned index)
    77           : string(string),
    78             index(index)
    79         {
    80         }
    81     };
    82 
    83     struct Policy
    84     {
    85         typedef Entry Payload;
    86 
    87         static uint32 hash(String *string) {
    88             return HashPointer(string);
    89         }
    90         
    91         static bool matches(String *key, Entry &e) {
    92             return key == e.string;
    93         }
    94     };
    95 
    96     typedef HashTable<Policy, ZoneAllocatorPolicy> Set;
    97 
    98   public:
    99     StringTable();
   100     bool initialize();
   101     void accept(VirtualObjectVisitor *visitor);
   102 
   103     bool add(Handle<String> name, unsigned *indexp);
   104     size_t stringCount() const {
   105         return strings_.length();
   106     }
   107     String *stringAt(size_t i) const {
   108         return strings_[i].string;
   109     }
   110 
   111   private:
   112     Set set_;
   113     Vector<Entry> strings_;
   114     bool initialized_;
   115 };
   116 
   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
   122 {
   123   private:
   124     PoolAllocator &pool_;
   125 
   126     bytecode *buffer_;
   127     bytecode *buffer_pos_;
   128     bytecode *buffer_end_;
   129     bytecode inline_buffer_[512];
   130     bool oom_;
   131     unsigned maxStackDepth_;
   132     Vector<bool> oopMap_;
   133     Vector<OopRecord *> oopRecords_;
   134     CompactBufferWriter sourcemap_;
   135     unsigned lastCodePosition_;
   136     unsigned firstLine_;
   137     StringTable strings_;
   138     Vector<Symbol *> locals_;
   139     Vector<Object *> objects_;
   140 
   141   private:
   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;
   148 
   149   private:
   150     bool growBuffer(size_t bytes);
   151 
   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);
   157         return true;
   158     }
   159 
   160     void writeUint8(unsigned value) {
   161         assert(value <= UCHAR_MAX);
   162         *buffer_pos_++ = value;
   163     }
   164     void writeFloat(float value) {
   165         *(float *)buffer_pos_ = value;
   166         buffer_pos_ += sizeof(float);
   167     }
   168     void writeInt32(int value) {
   169         *(int *)buffer_pos_ = value;
   170         buffer_pos_ += sizeof(int);
   171     }
   172     void writeUint32(unsigned value) {
   173         *(unsigned *)buffer_pos_ = value;
   174         buffer_pos_ += sizeof(unsigned);
   175     }
   176     void writeOp(Opcode op) {
   177         if (oom_)
   178             return;
   179 
   180         writeUint8(op);
   181         for (int i = 0; i < OpcodeInfo[op].nuses; i++)
   182             oopMap_.pop();
   183         for (int i = 0; i < OpcodeInfo[op].ndefs; i++)
   184             oopMap_.append(false);
   185         if (oopMap_.length() > maxStackDepth_)
   186             maxStackDepth_ = oopMap_.length();
   187     }
   188     void writeObject(Object *obj) {
   189         writeUint32(objects_.length());
   190         ScopedRoot<Object> root(obj);
   191         if (!objects_.append(root))
   192             oom_ = true;
   193     }
   194 
   195     int position() const {
   196         assert(buffer_pos_ - buffer_ < INT_MAX / 2);
   197         return int(buffer_pos_ - buffer_);
   198     }
   199 
   200   public:
   201     BytecodeEmitter(PoolAllocator &pool);
   202     ~BytecodeEmitter();
   203 
   204     void accept(VirtualObjectVisitor *visitor);
   205 
   206     bytecode *buffer() const {
   207         return buffer_;
   208     }
   209     unsigned length() const {
   210         return unsigned(buffer_pos_ - buffer_);
   211     }
   212     bool oom() const {
   213         return oom_ || sourcemap_.oom();
   214     }
   215     unsigned stackDepth() const {
   216         return oopMap_.length();
   217     }
   218     unsigned maxStackDepth() const {
   219         return maxStackDepth_;
   220     }
   221 
   222     void drop(unsigned amt) {
   223         assert(amt <= stackDepth());
   224         for (unsigned i = 0; i < amt; i++)
   225             oopMap_.pop();
   226     }
   227 
   228     void note_position(const SourcePosition &pos);
   229     void setFirstLine(unsigned line) {
   230         assert(!sourcemap_.length());
   231         firstLine_ = line;
   232     }
   233 
   234   public:
   235     // A label represents a local control-flow target in the bytecode. A label
   236     // may be in three states:
   237     //
   238     // (1) Empty - the label is not used yet.
   239     // (2) Pending - the label has incoming jumps, but the actual location of
   240     //               is not yet known. The list of jumps is threaded through
   241     //               the four bytes reserved for each emitted jump target. In
   242     //               this case, the offset field is the location of the most
   243     //               recently emitted incoming jump.
   244     // (3) Bound   - the label's position has been pinned.
   245     //
   246     // A jump can be emitted to a label in any state. Binding a label
   247     // immediately backpatches all pending incoming jumps. A label must be
   248     // bound if it is used.
   249     class Label
   250     {
   251         int offset_ : 31;
   252         bool bound_ : 1;
   253 
   254         void setOffset(int offset) {
   255             offset_ = offset;
   256             assert(offset_ == offset);
   257         }
   258 
   259       public:
   260         static const int INVALID_OFFSET = -1;
   261 
   262       public:
   263         Label()
   264           : offset_(INVALID_OFFSET),
   265             bound_(false)
   266         {
   267         }
   268         ~Label()
   269         {
   270             assert(bound_ || offset_ == INVALID_OFFSET);
   271         }
   272         
   273         bool bound() const {
   274             return bound_;
   275         }
   276         int offset() const {
   277             return offset_;
   278         }
   279         void bind(int offset) {
   280             assert(!bound_);
   281             setOffset(offset);
   282             bound_ = true;
   283         }
   284         int link(int offset) {
   285             assert(!bound_);
   286             int old = offset_;
   287             setOffset(offset);
   288             return old;
   289         }
   290     };
   291 
   292   private:
   293     int patchJumpAt(int at, int to) {
   294         assert(at >= 0 && at < position());
   295         int old = *(int *)(buffer_ + at + 1);
   296         *(int *)(buffer_ + at + 1) = (to - at);
   297         return old;
   298     }
   299 
   300     void singleByteOp(Opcode op) {
   301         assert(OpcodeInfo[op].length == 1);
   302         ensure(OpcodeInfo[op].length);
   303         writeOp(op);
   304     }
   305 
   306     // Mark a stack slot as having an object pointer.
   307     void markOop(unsigned depth, bool oop = true) {
   308         if (oom_)
   309             return;
   310         oopMap_[oopMap_.length() - depth] = oop;
   311     }
   312     bool getOop(unsigned depth) {
   313         if (oom_)
   314             return false;
   315         return oopMap_[oopMap_.length() - depth];
   316     }
   317 
   318     // Mark the current bytecode position as either re-entrant (meaning, it
   319     // can leave the interpreter or call to another function), or causing GC.
   320     // This will record which stack slots have objects and associate that
   321     // information with the current pc.
   322     void recordOops();
   323 
   324   public:
   325     void int_(int value) {
   326         ensure(OP_INT);
   327         writeOp(OP_INT);
   328         writeInt32(value);
   329     }
   330     void return_() {
   331         ensure(OP_RETURN);
   332         writeOp(OP_RETURN);
   333     }
   334     void getlocal(VariableSymbol *var);
   335     void setlocal(VariableSymbol *var);
   336     void getarg(VariableSymbol *var);
   337     void setarg(VariableSymbol *var);
   338 
   339     void j(Opcode op, Label *label) {
   340         // Since jumps can skip around the stream, do not try to do anything
   341         // in a potentially truncated state.
   342         if (oom())
   343             return;
   344 
   345         assert(op == OP_JT || op == OP_JF || op == OP_JUMP);
   346         ensure(OP_JUMP_LENGTH);
   347 
   348         if (label->bound()) {
   349             // We can immediately emit this jump.
   350             int distance = label->offset() - position();
   351             writeOp(op);
   352             writeInt32(distance);
   353         } else {
   354             // We can't emit this jump yet. Add a placeholder.
   355             int old = label->link(position());
   356             writeOp(op);
   357             writeInt32(old);
   358         }
   359     }
   360     void bind(Label *label) {
   361         if (oom())
   362             return;
   363 
   364         assert(!label->bound());
   365 
   366         int offset = label->offset();
   367         while (offset != Label::INVALID_OFFSET)
   368             offset = patchJumpAt(offset, position());
   369 
   370         label->bind(position());
   371     }
   372     void jump(Label *label) {
   373         j(OP_JUMP, label);
   374     }
   375 
   376     void binary(Opcode op) {
   377         singleByteOp(op);
   378     }
   379     void unary(Opcode op) {
   380         singleByteOp(op);
   381     }
   382 
   383     void pop() {
   384         singleByteOp(OP_POP);
   385     }
   386     void stop() {
   387         singleByteOp(OP_STOP);
   388     }
   389     void call(Handle<FunctionType> fun, unsigned argc) {
   390         recordOops();
   391 
   392         if (fun->isNative()) {
   393             ensure(OP_CALLNATIVE_LENGTH);
   394             writeOp(OP_CALLNATIVE);
   395             writeUint32(argc);
   396             drop(argc + 1);
   397         } else {
   398             ensure(OP_CALL_LENGTH);
   399             writeOp(OP_CALL);
   400             drop(argc + 1);
   401 
   402             if (fun->returnType()->isVoid())
   403                 drop(1);
   404             else if (fun->returnType()->isTraceable())
   405                 markOop(1);
   406         }
   407     }
   408 
   409     void getelem(Type *type) {
   410         singleByteOp(OP_GETELEM);
   411 
   412         if (type->isTraceable())
   413             markOop(1);
   414     }
   415     void setelem(Type *type) {
   416         singleByteOp(OP_SETELEM);
   417     }
   418 
   419     void getfield(unsigned index, Type *type) {
   420         ensure(OP_GETFIELD_LENGTH);
   421         writeOp(OP_GETFIELD);
   422         writeUint32(index);
   423 
   424         if (type->isTraceable())
   425             markOop(1);
   426     }
   427     void setfield(unsigned index, Type *type) {
   428         ensure(OP_SETFIELD_LENGTH);
   429         writeOp(OP_SETFIELD);
   430         writeUint32(index);
   431 
   432         if (type->isTraceable())
   433             markOop(1);
   434     }
   435 
   436 #if 0
   437     void getglobal(Variable *var) {
   438         ensure(OP_GETGLOBAL_F_LENGTH);
   439         if (var->type()->isPrimitive()) {
   440             switch (var->type()->primitive()) {
   441               case PrimitiveType_Float:
   442                 writeOp(OP_GETGLOBAL_F);
   443                 break;
   444               default:
   445                 assert(var->type()->primitive() == PrimitiveType_Int32);
   446                 writeOp(OP_GETGLOBAL_I);
   447                 break;
   448             }
   449         } else {
   450             writeOp(OP_GETGLOBAL_O);
   451             markOop(1);
   452         }
   453         writeUint32(var->slot());
   454     }
   455     void setglobal(Variable *var) {
   456         ensure(OP_SETGLOBAL_F_LENGTH);
   457         if (var->type()->isPrimitive()) {
   458             switch (var->type()->primitive()) {
   459               case PrimitiveType_Float:
   460                 writeOp(OP_SETGLOBAL_F);
   461                 break;
   462               default:
   463                 assert(var->type()->primitive() == PrimitiveType_Int32);
   464                 writeOp(OP_SETGLOBAL_I);
   465                 break;
   466             }
   467         } else {
   468             writeOp(OP_SETGLOBAL_O);
   469         }
   470         writeUint32(var->slot());
   471     }
   472 #endif
   473 
   474     void float_(float value) {
   475         ensure(OP_FLOAT_LENGTH);
   476         writeOp(OP_FLOAT);
   477         writeFloat(value);
   478     }
   479     void cvt_i2f() {
   480         singleByteOp(OP_CVT_I2F);
   481     }
   482     void newarray(Opcode op, Handle<ArrayMap> map, Heap::Tenure tenure) {
   483         assert(op == OP_NEWFIXED ||
   484                op == OP_NEWEMPTY ||
   485                op == OP_NEWSIZED);
   486 
   487         recordOops();
   488         ensure(OpcodeInfo[op].length);
   489         writeOp(op);
   490         writeUint8(tenure);
   491         writeObject(map);
   492 
   493         if (op == OP_NEWSIZED)
   494             drop(map->type()->levels());
   495 
   496         markOop(1);
   497     }
   498     void newstruct(Handle<Map> map, Heap::Tenure tenure) {
   499         recordOops();
   500         ensure(OP_NEWSTRUCT_LENGTH);
   501         writeOp(OP_NEWSTRUCT);
   502         writeUint8(tenure);
   503         writeObject(map);
   504         markOop(1);
   505     }
   506     void savelifo(unsigned slot) {
   507         ensure(OP_SAVELIFO_LENGTH);
   508         writeOp(OP_SAVELIFO);
   509         writeUint32(slot);
   510     }
   511     void unwindlifo(unsigned slot) {
   512         ensure(OP_UNWINDLIFO_LENGTH);
   513         writeOp(OP_UNWINDLIFO);
   514         writeUint32(slot);
   515     }
   516 #if 0
   517     void newref(Variable *var) {
   518         recordOops();
   519         if (var->location() == Variable::STACK) {
   520             ensure(OP_VARREF_LIFO_LENGTH);
   521             writeOp(OP_VARREF_LIFO);
   522         } else {
   523             assert(var->location() == Variable::PARAMETER);
   524             ensure(OP_ARGREF_LIFO_LENGTH);
   525             writeOp(OP_ARGREF_LIFO);
   526         }
   527         writeUint32(var->slot());
   528         markOop(1);
   529     }
   530 #endif
   531 
   532     void slotref_lifo() {
   533         recordOops();
   534         singleByteOp(OP_SLOTREF_LIFO);
   535         markOop(1);
   536     }
   537     void getref(Type *type) {
   538         if (type->pod() == PrimitiveType_Int32) {
   539             singleByteOp(OP_GETREF_I);
   540         } else {
   541             assert(type->pod() == PrimitiveType_Float);
   542             singleByteOp(OP_GETREF_F);
   543         }
   544     }
   545     void setref(Type *type) {
   546         if (type->pod() == PrimitiveType_Int32) {
   547             singleByteOp(OP_SETREF_I);
   548         } else {
   549             assert(type->pod() == PrimitiveType_Float);
   550             singleByteOp(OP_SETREF_F);
   551         }
   552     }
   553     void object(Handle<Object> obj) {
   554         ensure(OP_OBJECT_LENGTH);
   555         writeOp(OP_OBJECT);
   556         writeObject(obj);
   557         markOop(1);
   558     }
   559     void copyarray() {
   560         singleByteOp(OP_COPYARRAY);
   561         markOop(1);
   562     }
   563     void copystruct() {
   564         singleByteOp(OP_COPYSTRUCT);
   565         markOop(1);
   566     }
   567     void sizeof_() {
   568         singleByteOp(OP_SIZEOF);
   569     }
   570 
   571     void dup() {
   572         bool oop = getOop(1);
   573         singleByteOp(OP_DUP);
   574         markOop(1, oop);
   575     }
   576     void dup2() {
   577         bool oop2 = getOop(2);
   578         bool oop1 = getOop(1);
   579 
   580         singleByteOp(OP_DUP2);
   581 
   582         markOop(2, oop2);
   583         markOop(1, oop1);
   584     }
   585     void swap() {
   586         bool oop2 = getOop(2);
   587         bool oop1 = getOop(1);
   588 
   589         singleByteOp(OP_SWAP);
   590 
   591         markOop(2, oop1);
   592         markOop(1, oop2);
   593     }
   594     void roll3() {
   595         bool oop3 = getOop(3);
   596         bool oop2 = getOop(2);
   597         bool oop1 = getOop(1);
   598 
   599         singleByteOp(OP_ROLL3);
   600 
   601         markOop(3, oop2);
   602         markOop(2, oop1);
   603         markOop(1, oop3);
   604     }
   605     void pick2() {
   606         bool oop2 = getOop(2);
   607         bool oop1 = getOop(1);
   608 
   609         singleByteOp(OP_PICK2);
   610 
   611         markOop(3, oop2);
   612         markOop(2, oop1);
   613         markOop(1, oop2);
   614     }
   615     void pick3() {
   616         bool oop3 = getOop(3);
   617         bool oop2 = getOop(2);
   618         bool oop1 = getOop(1);
   619 
   620         singleByteOp(OP_PICK3);
   621 
   622         markOop(4, oop3);
   623         markOop(3, oop2);
   624         markOop(2, oop1);
   625         markOop(1, oop3);
   626     }
   627 
   628     void returnvoid() {
   629         singleByteOp(OP_RETURNVOID);
   630     }
   631     void bitnot() {
   632         singleByteOp(OP_BITNOT);
   633     }
   634     void not_() {
   635         singleByteOp(OP_NOT);
   636     }
   637     void not_f() {
   638         singleByteOp(OP_NOT_F);
   639     }
   640     void neg() {
   641         singleByteOp(OP_NEG);
   642     }
   643     void neg_f() {
   644         singleByteOp(OP_NEG_F);
   645     }
   646     void bits_i2f() {
   647         singleByteOp(OP_BITS_I2F);
   648     }
   649     void bits_f2i() {
   650         singleByteOp(OP_BITS_F2I);
   651     }
   652     void true_() {
   653         singleByteOp(OP_TRUE);
   654     }
   655     void false_() {
   656         singleByteOp(OP_FALSE);
   657     }
   658     
   659     unsigned addString(Handle<String> name) {
   660         unsigned index;
   661         if (!strings_.add(name, &index)) {
   662             oom_ |= true;
   663             return 0;
   664         }
   665         return index;
   666     }
   667 
   668     void getglobal(Symbol *sym);
   669     void setglobal(Symbol *sym);
   670 
   671     void public_() {
   672         recordOops();
   673         singleByteOp(OP_PUBLIC);
   674     }
   675 
   676     void tableswitch(int low, int high, Label *def, Label **labels) {
   677         unsigned tablesize = TableSwitchEntries(low, high);
   678         assert(tablesize <= MAX_TABLESWITCH_ENTRIES);
   679 
   680         ensure(OP_TABLESWITCH_LENGTH);
   681         writeOp(OP_TABLESWITCH);
   682         writeInt32(low);
   683         writeInt32(high);
   684         jump(def);
   685 
   686         // When labels are patched, we assume each position is a jump. Rather
   687         // than hack position offsets to make labels work without actual
   688         // incoming jumps, we emit a jump inline.
   689         for (unsigned i = 0; i < tablesize; i++)
   690             jump(labels[i]);
   691     }
   692 
   693     bool allocate(VariableSymbol *sym);
   694 
   695     Code *finish();
   696 
   697     // Helpers.
   698 #if 0
   699     void get(Variable *var) {
   700         if (var->location() == Variable::STACK) {
   701             getlocal(var);
   702         } else {
   703             assert(var->location() == Variable::PARAMETER);
   704             getarg(var);
   705         }
   706     }
   707     void set(Variable *var) {
   708         assert(!var->type()->isReference());
   709         if (var->location() == Variable::STACK) {
   710             setlocal(var);
   711         } else {
   712             assert(var->location() == Variable::PARAMETER);
   713             setarg(var);
   714         }
   715     }
   716 #endif
   717 };
   718 
   719 }
   720 
   721 #endif // _include_bytecode_emitter_h_