src/compiler/BytecodeEmitter.h
author Asher Baker <asherkin@gmail.com>
Mon Jun 10 15:52:44 2013 +0100 (2013-06-10)
changeset 265 3a903b89a514
parent 263 ba85a47ee414
permissions -rw-r--r--
Fixed type checking for multidimensional arrays.
     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     bytecode *buffer_;
   125     bytecode *buffer_pos_;
   126     bytecode *buffer_end_;
   127     bytecode inline_buffer_[512];
   128     bool oom_;
   129     unsigned maxStackDepth_;
   130     Vector<bool> oopMap_;
   131     Vector<OopRecord *> oopRecords_;
   132     CompactBufferWriter sourcemap_;
   133     unsigned lastCodePosition_;
   134     unsigned firstLine_;
   135     StringTable strings_;
   136     Vector<Symbol *> locals_;
   137     Vector<Object *> objects_;
   138     unsigned loopDepth_;
   139     unsigned maxLoopDepth_;
   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         assert(obj);
   190 
   191         writeUint32(objects_.length());
   192         if (!objects_.append(obj))
   193             oom_ = true;
   194     }
   195 
   196     int position() const {
   197         assert(buffer_pos_ - buffer_ < INT_MAX / 2);
   198         return int(buffer_pos_ - buffer_);
   199     }
   200 
   201   public:
   202     BytecodeEmitter();
   203     ~BytecodeEmitter();
   204 
   205     void accept(VirtualObjectVisitor *visitor);
   206 
   207     bytecode *buffer() const {
   208         return buffer_;
   209     }
   210     unsigned length() const {
   211         return unsigned(buffer_pos_ - buffer_);
   212     }
   213     bool oom() const {
   214         return oom_ || sourcemap_.oom();
   215     }
   216     unsigned stackDepth() const {
   217         return oopMap_.length();
   218     }
   219     unsigned maxStackDepth() const {
   220         return maxStackDepth_;
   221     }
   222 
   223     void drop(unsigned amt) {
   224         assert(amt <= stackDepth());
   225         for (unsigned i = 0; i < amt; i++)
   226             oopMap_.pop();
   227     }
   228 
   229     void note_position(const SourcePosition &pos);
   230     void setFirstLine(unsigned line) {
   231         assert(!sourcemap_.length());
   232         firstLine_ = line;
   233     }
   234 
   235   public:
   236     // A label represents a local control-flow target in the bytecode. A label
   237     // may be in three states:
   238     //
   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.
   246     //
   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.
   250     class Label
   251     {
   252         int offset_ : 31;
   253         bool bound_ : 1;
   254 
   255         void setOffset(int offset) {
   256             offset_ = offset;
   257             assert(offset_ == offset);
   258         }
   259 
   260       public:
   261         static const int INVALID_OFFSET = -1;
   262 
   263       public:
   264         Label()
   265           : offset_(INVALID_OFFSET),
   266             bound_(false)
   267         {
   268         }
   269         ~Label()
   270         {
   271             assert(bound_ || offset_ == INVALID_OFFSET);
   272         }
   273         
   274         bool bound() const {
   275             return bound_;
   276         }
   277         int offset() const {
   278             return offset_;
   279         }
   280         void bind(int offset) {
   281             assert(!bound_);
   282             setOffset(offset);
   283             bound_ = true;
   284         }
   285         int link(int offset) {
   286             assert(!bound_);
   287             int old = offset_;
   288             setOffset(offset);
   289             return old;
   290         }
   291     };
   292 
   293   private:
   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);
   298         return old;
   299     }
   300 
   301     void singleByteOp(Opcode op) {
   302         assert(OpcodeInfo[op].length == 1);
   303         ensure(OpcodeInfo[op].length);
   304         writeOp(op);
   305     }
   306 
   307     // Mark a stack slot as having an object pointer.
   308     void markOop(unsigned depth, bool oop = true) {
   309         if (oom_)
   310             return;
   311         oopMap_[oopMap_.length() - depth] = oop;
   312     }
   313     bool getOop(unsigned depth) {
   314         if (oom_)
   315             return false;
   316         return oopMap_[oopMap_.length() - depth];
   317     }
   318 
   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.
   323     void recordOops();
   324 
   325   public:
   326     void int_(int value) {
   327         ensure(OP_INT);
   328         writeOp(OP_INT);
   329         writeInt32(value);
   330     }
   331     void return_() {
   332         ensure(OP_RETURN);
   333         writeOp(OP_RETURN);
   334     }
   335     void getlocal(VariableSymbol *var);
   336     void setlocal(VariableSymbol *var);
   337     void getarg(VariableSymbol *var);
   338     void setarg(VariableSymbol *var);
   339 
   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.
   343         if (oom())
   344             return;
   345 
   346         assert(op == OP_JT || op == OP_JF || op == OP_JUMP ||
   347                op == OP_CONTINUE || op == OP_BREAK);
   348         ensure(OP_JUMP_LENGTH);
   349 
   350         if (label->bound()) {
   351             // We can immediately emit this jump.
   352             int distance = label->offset() - position();
   353             writeOp(op);
   354             writeInt32(distance);
   355         } else {
   356             // We can't emit this jump yet. Add a placeholder.
   357             int old = label->link(position());
   358             writeOp(op);
   359             writeInt32(old);
   360         }
   361     }
   362     void bind(Label *label) {
   363         if (oom())
   364             return;
   365 
   366         assert(!label->bound());
   367 
   368         int offset = label->offset();
   369         while (offset != Label::INVALID_OFFSET)
   370             offset = patchJumpAt(offset, position());
   371 
   372         label->bind(position());
   373     }
   374     void jump(Label *label) {
   375         j(OP_JUMP, label);
   376     }
   377 
   378     void binary(Opcode op) {
   379         singleByteOp(op);
   380     }
   381     void unary(Opcode op) {
   382         singleByteOp(op);
   383     }
   384 
   385     void pop() {
   386         singleByteOp(OP_POP);
   387     }
   388     void stop() {
   389         singleByteOp(OP_STOP);
   390     }
   391     void call(Handle<FunctionType> fun, unsigned argc) {
   392         recordOops();
   393 
   394         if (fun->isNative()) {
   395             ensure(OP_CALLNATIVE_LENGTH);
   396             writeOp(OP_CALLNATIVE);
   397             writeUint32(argc);
   398             drop(argc + 1);
   399         } else {
   400             ensure(OP_CALL_LENGTH);
   401             writeOp(OP_CALL);
   402             drop(argc + 1);
   403 
   404             if (fun->returnType()->isVoid())
   405                 drop(1);
   406             else if (fun->returnType()->isTraceable())
   407                 markOop(1);
   408         }
   409     }
   410 
   411     void getelem(Type *type) {
   412         singleByteOp(OP_GETELEM);
   413 
   414         if (type->isTraceable())
   415             markOop(1);
   416     }
   417     void setelem(Type *type) {
   418         singleByteOp(OP_SETELEM);
   419     }
   420 
   421     void getfield(unsigned index, Type *type) {
   422         ensure(OP_GETFIELD_LENGTH);
   423         writeOp(OP_GETFIELD);
   424         writeUint32(index);
   425 
   426         if (type->isTraceable())
   427             markOop(1);
   428     }
   429     void setfield(unsigned index, Type *type) {
   430         ensure(OP_SETFIELD_LENGTH);
   431         writeOp(OP_SETFIELD);
   432         writeUint32(index);
   433 
   434         if (type->isTraceable())
   435             markOop(1);
   436     }
   437 
   438     int enterloop() {
   439         int offset = position();
   440 
   441         ensure(OP_ENTERLOOP);
   442         writeOp(OP_ENTERLOOP);
   443         writeUint8(0);
   444 
   445         loopDepth_++;
   446         if (loopDepth_ > maxLoopDepth_)
   447             maxLoopDepth_ = loopDepth_;
   448 
   449         return offset;
   450     }
   451     void leaveloop() {
   452         singleByteOp(OP_LEAVELOOP);
   453 
   454         assert(loopDepth_);
   455         loopDepth_--;
   456     }
   457     void setLoopUsesLifoStack(int pos) {
   458         assert(pos >= 0 && pos < position());
   459         assert(*(buffer() + pos) == OP_ENTERLOOP);
   460         *(buffer() + pos + 1) = 1;
   461     }
   462 
   463     void float_(float value) {
   464         ensure(OP_FLOAT_LENGTH);
   465         writeOp(OP_FLOAT);
   466         writeFloat(value);
   467     }
   468     void cvt_i2f() {
   469         singleByteOp(OP_CVT_I2F);
   470     }
   471     void newarray(Opcode op, Handle<ArrayMap> map, Heap::Tenure tenure) {
   472         assert(op == OP_NEWFIXED ||
   473                op == OP_NEWEMPTY ||
   474                op == OP_NEWSIZED);
   475 
   476         recordOops();
   477         ensure(OpcodeInfo[op].length);
   478         writeOp(op);
   479         writeUint8(tenure);
   480         writeObject(map);
   481 
   482         if (op == OP_NEWSIZED)
   483             drop(map->type()->levels());
   484 
   485         markOop(1);
   486     }
   487     void newstruct(Handle<Map> map, Heap::Tenure tenure) {
   488         recordOops();
   489         ensure(OP_NEWSTRUCT_LENGTH);
   490         writeOp(OP_NEWSTRUCT);
   491         writeUint8(tenure);
   492         writeObject(map);
   493         markOop(1);
   494     }
   495     void deparray(ArrayMap *map) {
   496         recordOops();
   497         ensure(OP_DEPARRAY_LENGTH);
   498         writeOp(OP_DEPARRAY);
   499         writeObject(map);
   500         markOop(1);
   501     }
   502     void savelifo(unsigned slot) {
   503         ensure(OP_SAVELIFO_LENGTH);
   504         writeOp(OP_SAVELIFO);
   505         writeUint32(slot);
   506     }
   507     void unwindlifo(unsigned slot) {
   508         ensure(OP_UNWINDLIFO_LENGTH);
   509         writeOp(OP_UNWINDLIFO);
   510         writeUint32(slot);
   511     }
   512 
   513     void newref(VariableSymbol *var);
   514 
   515     void slotref_lifo() {
   516         recordOops();
   517         singleByteOp(OP_SLOTREF_LIFO);
   518         markOop(1);
   519     }
   520     void getref(Type *type) {
   521         if (type->pod() == PrimitiveType_Int32) {
   522             singleByteOp(OP_GETREF_I);
   523         } else {
   524             assert(type->pod() == PrimitiveType_Float);
   525             singleByteOp(OP_GETREF_F);
   526         }
   527     }
   528     void setref(Type *type) {
   529         if (type->pod() == PrimitiveType_Int32) {
   530             singleByteOp(OP_SETREF_I);
   531         } else {
   532             assert(type->pod() == PrimitiveType_Float);
   533             singleByteOp(OP_SETREF_F);
   534         }
   535     }
   536     void object(Handle<Object> obj) {
   537         assert(obj);
   538 
   539         ensure(OP_OBJECT_LENGTH);
   540         writeOp(OP_OBJECT);
   541         writeObject(obj);
   542         markOop(1);
   543     }
   544     void duparray() {
   545         singleByteOp(OP_DUPARRAY);
   546         markOop(1);
   547     }
   548     void copyarray() {
   549         singleByteOp(OP_COPYARRAY);
   550         markOop(1);
   551     }
   552     void copystruct() {
   553         singleByteOp(OP_COPYSTRUCT);
   554         markOop(1);
   555     }
   556     void sizeof_() {
   557         singleByteOp(OP_SIZEOF);
   558     }
   559 
   560     void dup() {
   561         bool oop = getOop(1);
   562         singleByteOp(OP_DUP);
   563         markOop(1, oop);
   564     }
   565     void dup2() {
   566         bool oop2 = getOop(2);
   567         bool oop1 = getOop(1);
   568 
   569         singleByteOp(OP_DUP2);
   570 
   571         markOop(2, oop2);
   572         markOop(1, oop1);
   573     }
   574     void swap() {
   575         bool oop2 = getOop(2);
   576         bool oop1 = getOop(1);
   577 
   578         singleByteOp(OP_SWAP);
   579 
   580         markOop(2, oop1);
   581         markOop(1, oop2);
   582     }
   583     void roll3() {
   584         bool oop3 = getOop(3);
   585         bool oop2 = getOop(2);
   586         bool oop1 = getOop(1);
   587 
   588         singleByteOp(OP_ROLL3);
   589 
   590         markOop(3, oop2);
   591         markOop(2, oop1);
   592         markOop(1, oop3);
   593     }
   594     void pick2() {
   595         bool oop2 = getOop(2);
   596         bool oop1 = getOop(1);
   597 
   598         singleByteOp(OP_PICK2);
   599 
   600         markOop(3, oop2);
   601         markOop(2, oop1);
   602         markOop(1, oop2);
   603     }
   604     void pick3() {
   605         bool oop3 = getOop(3);
   606         bool oop2 = getOop(2);
   607         bool oop1 = getOop(1);
   608 
   609         singleByteOp(OP_PICK3);
   610 
   611         markOop(4, oop3);
   612         markOop(3, oop2);
   613         markOop(2, oop1);
   614         markOop(1, oop3);
   615     }
   616 
   617     void returnvoid() {
   618         singleByteOp(OP_RETURNVOID);
   619     }
   620     void bitnot() {
   621         singleByteOp(OP_BITNOT);
   622     }
   623     void not_() {
   624         singleByteOp(OP_NOT);
   625     }
   626     void not_f() {
   627         singleByteOp(OP_NOT_F);
   628     }
   629     void neg() {
   630         singleByteOp(OP_NEG);
   631     }
   632     void neg_f() {
   633         singleByteOp(OP_NEG_F);
   634     }
   635     void true_() {
   636         singleByteOp(OP_TRUE);
   637     }
   638     void false_() {
   639         singleByteOp(OP_FALSE);
   640     }
   641     
   642     unsigned addString(Handle<String> name) {
   643         unsigned index;
   644         if (!strings_.add(name, &index)) {
   645             oom_ |= true;
   646             return 0;
   647         }
   648         return index;
   649     }
   650 
   651     void getglobal(Symbol *sym);
   652     void setglobal(Symbol *sym);
   653 
   654     void public_() {
   655         recordOops();
   656         singleByteOp(OP_PUBLIC);
   657     }
   658 
   659     void bitcast(Type *type) {
   660         ensure(OP_BITCAST_LENGTH);
   661         writeOp(OP_BITCAST);
   662         writeObject(type);
   663     }
   664 
   665     void tableswitch(int low, int high, Label *def, Label **labels) {
   666         unsigned tablesize = TableSwitchEntries(low, high);
   667         assert(tablesize <= MAX_TABLESWITCH_ENTRIES);
   668 
   669         ensure(OP_TABLESWITCH_LENGTH);
   670         writeOp(OP_TABLESWITCH);
   671         writeInt32(low);
   672         writeInt32(high);
   673         jump(def);
   674 
   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++)
   679             jump(labels[i]);
   680     }
   681 
   682     void import(unsigned index) {
   683         ensure(OP_IMPORT_LENGTH);
   684         writeOp(OP_IMPORT);
   685         writeUint32(index);
   686         markOop(1);
   687     }
   688 
   689     bool allocate(VariableSymbol *sym);
   690 
   691     Code *finish();
   692 
   693     // Helpers.
   694 #if 0
   695     void get(Variable *var) {
   696         if (var->location() == Variable::STACK) {
   697             getlocal(var);
   698         } else {
   699             assert(var->location() == Variable::PARAMETER);
   700             getarg(var);
   701         }
   702     }
   703     void set(Variable *var) {
   704         assert(!var->type()->isReference());
   705         if (var->location() == Variable::STACK) {
   706             setlocal(var);
   707         } else {
   708             assert(var->location() == Variable::PARAMETER);
   709             setarg(var);
   710         }
   711     }
   712 #endif
   713 };
   714 
   715 }
   716 
   717 #endif // _include_bytecode_emitter_h_