jitcraft/BytecodeEmitter.h
changeset 47 050939c6181e
parent 46 735503e448a0
child 58 4d6265f95ff1
     1.1 --- a/jitcraft/BytecodeEmitter.h	Tue Jul 03 13:53:34 2012 -0400
     1.2 +++ b/jitcraft/BytecodeEmitter.h	Wed Jul 04 19:39:00 2012 -0400
     1.3 @@ -33,18 +33,41 @@
     1.4  
     1.5  typedef std::vector<ScopedRoot<Object> *> ObjectList;
     1.6  
     1.7 +struct OopRecord : public PoolObject
     1.8 +{
     1.9 +    unsigned depth;
    1.10 +    unsigned offset;
    1.11 +    bool *slots;
    1.12 +
    1.13 +    OopRecord(unsigned length, unsigned offset)
    1.14 +      : depth(length),
    1.15 +        offset(offset),
    1.16 +        slots(NULL)
    1.17 +    {
    1.18 +    }
    1.19 +};
    1.20 +
    1.21  class BytecodeEmitter
    1.22  {
    1.23 +  private:
    1.24 +    PoolAllocator &pool_;
    1.25 +
    1.26      bytecode *buffer_;
    1.27      bytecode *buffer_pos_;
    1.28      bytecode *buffer_end_;
    1.29      bytecode inline_buffer_[512];
    1.30      bool oom_;
    1.31      unsigned maxStackDepth_;
    1.32 -    unsigned stackDepth_;
    1.33      ObjectList objects_;
    1.34 +    std::vector<bool> oopMap_;
    1.35 +    std::vector<OopRecord *> oopRecords_;
    1.36  
    1.37    private:
    1.38 +    // The maximum size of a code object must be such that the distance between
    1.39 +    // two instructions fits into a signed, 31-bit integer. This ensures that
    1.40 +    // all code-bounded buffers (like the number of object literals or
    1.41 +    // safepoints) does not need to be bounds checked. It also means we can add
    1.42 +    // any two offsets and be guaranteed that they don't overflow.
    1.43      static const size_t MAX_LENGTH = INT_MAX / 2;
    1.44  
    1.45    private:
    1.46 @@ -59,7 +82,7 @@
    1.47      }
    1.48  
    1.49      void writeUint8(unsigned value) {
    1.50 -        assert(value >= 0 && value <= UCHAR_MAX);
    1.51 +        assert(value <= UCHAR_MAX);
    1.52          *buffer_pos_++ = value;
    1.53      }
    1.54      void writeFloat(float value) {
    1.55 @@ -75,12 +98,16 @@
    1.56          buffer_pos_ += sizeof(unsigned);
    1.57      }
    1.58      void writeOp(Opcode op) {
    1.59 +        if (oom_)
    1.60 +            return;
    1.61 +
    1.62          writeUint8(op);
    1.63 -        stackDepth_ += OpcodeInfo[op].ndefs;
    1.64 -        if (OpcodeInfo[op].nuses != -1)
    1.65 -            stackDepth_ -= OpcodeInfo[op].nuses;
    1.66 -        if (stackDepth_ > maxStackDepth_)
    1.67 -            maxStackDepth_ = stackDepth_;
    1.68 +        for (int i = 0; i < OpcodeInfo[op].nuses; i++)
    1.69 +            oopMap_.pop_back();
    1.70 +        for (int i = 0; i < OpcodeInfo[op].ndefs; i++)
    1.71 +            oopMap_.push_back(false);
    1.72 +        if (oopMap_.size() > maxStackDepth_)
    1.73 +            maxStackDepth_ = oopMap_.size();
    1.74      }
    1.75      void writeObject(Object *obj) {
    1.76          writeUint32(objects_.size());
    1.77 @@ -96,7 +123,7 @@
    1.78      }
    1.79  
    1.80    public:
    1.81 -    BytecodeEmitter();
    1.82 +    BytecodeEmitter(PoolAllocator &pool);
    1.83  
    1.84      bytecode *buffer() const {
    1.85          return buffer_;
    1.86 @@ -108,7 +135,7 @@
    1.87          return oom_;
    1.88      }
    1.89      unsigned stackDepth() const {
    1.90 -        return stackDepth_;
    1.91 +        return oopMap_.size();
    1.92      }
    1.93      unsigned maxStackDepth() const {
    1.94          return maxStackDepth_;
    1.95 @@ -116,10 +143,14 @@
    1.96      const ObjectList *objects() const {
    1.97          return &objects_;
    1.98      }
    1.99 +    std::vector<OopRecord *> *oopRecords() {
   1.100 +        return &oopRecords_;
   1.101 +    }
   1.102  
   1.103      void drop(unsigned amt) {
   1.104 -        assert(amt <= stackDepth_);
   1.105 -        stackDepth_ -= amt;
   1.106 +        assert(amt <= stackDepth());
   1.107 +        for (unsigned i = 0; i < amt; i++)
   1.108 +            oopMap_.pop_back();
   1.109      }
   1.110  
   1.111    public:
   1.112 @@ -194,6 +225,24 @@
   1.113          writeOp(op);
   1.114      }
   1.115  
   1.116 +    // Mark a stack slot as having an object pointer.
   1.117 +    void markOop(unsigned depth, bool oop = true) {
   1.118 +        if (oom_)
   1.119 +            return;
   1.120 +        oopMap_[oopMap_.size() - depth] = oop;
   1.121 +    }
   1.122 +    bool getOop(unsigned depth) {
   1.123 +        if (oom_)
   1.124 +            return false;
   1.125 +        return oopMap_[oopMap_.size() - depth];
   1.126 +    }
   1.127 +
   1.128 +    // Mark the current bytecode position as either re-entrant (meaning, it
   1.129 +    // can leave the interpreter or call to another function), or causing GC.
   1.130 +    // This will record which stack slots have objects and associate that
   1.131 +    // information with the current pc.
   1.132 +    void recordOops();
   1.133 +
   1.134    public:
   1.135      void int_(int value) {
   1.136          ensure(OP_INT);
   1.137 @@ -204,25 +253,37 @@
   1.138          ensure(OP_RETURN);
   1.139          writeOp(OP_RETURN);
   1.140      }
   1.141 -    void getlocal(unsigned local) {
   1.142 +    void getlocal(Variable *var) {
   1.143          ensure(OP_GETLOCAL_LENGTH);
   1.144          writeOp(OP_GETLOCAL);
   1.145 -        writeUint32(local);
   1.146 +        writeUint32(var->slot());
   1.147 +
   1.148 +        if (var->type()->isTraceable())
   1.149 +            markOop(1);
   1.150      }
   1.151 -    void setlocal(unsigned local) {
   1.152 +    void setlocal(Variable *var) {
   1.153          ensure(OP_SETLOCAL_LENGTH);
   1.154          writeOp(OP_SETLOCAL);
   1.155 -        writeUint32(local);
   1.156 +        writeUint32(var->slot());
   1.157 +
   1.158 +        if (var->type()->isTraceable())
   1.159 +            markOop(1);
   1.160      }
   1.161 -    void getarg(unsigned slot) {
   1.162 +    void getarg(Variable *var) {
   1.163          ensure(OP_GETARG_LENGTH);
   1.164          writeOp(OP_GETARG);
   1.165 -        writeUint32(slot);
   1.166 +        writeUint32(var->slot());
   1.167 +
   1.168 +        if (var->type()->isTraceable())
   1.169 +            markOop(1);
   1.170      }
   1.171 -    void setarg(unsigned slot) {
   1.172 +    void setarg(Variable *var) {
   1.173          ensure(OP_SETARG_LENGTH);
   1.174          writeOp(OP_SETARG);
   1.175 -        writeUint32(slot);
   1.176 +        writeUint32(var->slot());
   1.177 +
   1.178 +        if (var->type()->isTraceable())
   1.179 +            markOop(1);
   1.180      }
   1.181  
   1.182      void j(Opcode op, Label *label) {
   1.183 @@ -273,6 +334,7 @@
   1.184          singleByteOp(OP_STOP);
   1.185      }
   1.186      void callglobal(unsigned index) {
   1.187 +        recordOops();
   1.188          ensure(OP_CALLGLOBAL_LENGTH);
   1.189          writeOp(OP_CALLGLOBAL);
   1.190          writeUint32(index);
   1.191 @@ -307,9 +369,11 @@
   1.192      }
   1.193      void getarray_o() {
   1.194          singleByteOp(OP_GETARRAY_O);
   1.195 +        markOop(1);
   1.196      }
   1.197      void bounds() {
   1.198          singleByteOp(OP_BOUNDS);
   1.199 +        markOop(2);
   1.200      }
   1.201      void float_(float value) {
   1.202          ensure(OP_FLOAT_LENGTH);
   1.203 @@ -320,9 +384,11 @@
   1.204          singleByteOp(OP_CVT_I2F);
   1.205      }
   1.206      void newarray_lifo(Handle<Map> map) {
   1.207 +        recordOops();
   1.208          ensure(OP_NEWARRAY_LIFO_LENGTH);
   1.209          writeOp(OP_NEWARRAY_LIFO);
   1.210          writeObject(map);
   1.211 +        markOop(1);
   1.212      }
   1.213      void savelifo(unsigned slot) {
   1.214          ensure(OP_SAVELIFO_LENGTH);
   1.215 @@ -335,6 +401,7 @@
   1.216          writeUint32(slot);
   1.217      }
   1.218      void newref(Variable *var) {
   1.219 +        recordOops();
   1.220          if (var->location() == Variable::STACK) {
   1.221              ensure(OP_VARREF_LIFO_LENGTH);
   1.222              writeOp(OP_VARREF_LIFO);
   1.223 @@ -344,29 +411,18 @@
   1.224              writeOp(OP_ARGREF_LIFO);
   1.225          }
   1.226          writeUint32(var->slot());
   1.227 -    }
   1.228 -    void get(Variable *var) {
   1.229 -        if (var->location() == Variable::STACK) {
   1.230 -            getlocal(var->slot());
   1.231 -        } else {
   1.232 -            assert(var->location() == Variable::PARAMETER);
   1.233 -            getarg(var->slot());
   1.234 -        }
   1.235 +        markOop(1);
   1.236      }
   1.237 -    void set(Variable *var) {
   1.238 -        assert(!var->type()->isReference());
   1.239 -        if (var->location() == Variable::STACK) {
   1.240 -            setlocal(var->slot());
   1.241 -        } else {
   1.242 -            assert(var->location() == Variable::PARAMETER);
   1.243 -            setarg(var->slot());
   1.244 -        }
   1.245 -    }
   1.246 +
   1.247      void slotref_lifo() {
   1.248 +        recordOops();
   1.249          singleByteOp(OP_SLOTREF_LIFO);
   1.250 +        markOop(1);
   1.251      }
   1.252      void arrayref_lifo() {
   1.253 +        recordOops();
   1.254          singleByteOp(OP_ARRAYREF_LIFO);
   1.255 +        markOop(1);
   1.256      }
   1.257      void getref(PrimitiveType type) {
   1.258          if (type == PrimitiveType_Int32) {
   1.259 @@ -388,27 +444,87 @@
   1.260          ensure(OP_OBJECT_LENGTH);
   1.261          writeOp(OP_OBJECT);
   1.262          writeObject(obj);
   1.263 +        markOop(1);
   1.264      }
   1.265      void arraycopy() {
   1.266          singleByteOp(OP_ARRAYCOPY);
   1.267 +        markOop(1);
   1.268      }
   1.269 +
   1.270      void dup() {
   1.271 +        bool oop = getOop(1);
   1.272          singleByteOp(OP_DUP);
   1.273 +        markOop(1, oop);
   1.274      }
   1.275      void dup2() {
   1.276 +        bool oop2 = getOop(2);
   1.277 +        bool oop1 = getOop(1);
   1.278 +
   1.279          singleByteOp(OP_DUP2);
   1.280 +
   1.281 +        markOop(2, oop2);
   1.282 +        markOop(1, oop1);
   1.283      }
   1.284      void swap() {
   1.285 +        bool oop2 = getOop(2);
   1.286 +        bool oop1 = getOop(1);
   1.287 +
   1.288          singleByteOp(OP_SWAP);
   1.289 +
   1.290 +        markOop(2, oop1);
   1.291 +        markOop(1, oop2);
   1.292      }
   1.293      void roll3() {
   1.294 +        bool oop3 = getOop(3);
   1.295 +        bool oop2 = getOop(2);
   1.296 +        bool oop1 = getOop(1);
   1.297 +
   1.298          singleByteOp(OP_ROLL3);
   1.299 +
   1.300 +        markOop(3, oop2);
   1.301 +        markOop(2, oop1);
   1.302 +        markOop(1, oop3);
   1.303      }
   1.304      void pick2() {
   1.305 +        bool oop2 = getOop(2);
   1.306 +        bool oop1 = getOop(1);
   1.307 +
   1.308          singleByteOp(OP_PICK2);
   1.309 +
   1.310 +        markOop(3, oop2);
   1.311 +        markOop(2, oop1);
   1.312 +        markOop(1, oop2);
   1.313      }
   1.314      void pick3() {
   1.315 +        bool oop3 = getOop(3);
   1.316 +        bool oop2 = getOop(2);
   1.317 +        bool oop1 = getOop(1);
   1.318 +
   1.319          singleByteOp(OP_PICK3);
   1.320 +
   1.321 +        markOop(4, oop3);
   1.322 +        markOop(3, oop2);
   1.323 +        markOop(2, oop1);
   1.324 +        markOop(1, oop3);
   1.325 +    }
   1.326 +
   1.327 +    // Helpers.
   1.328 +    void get(Variable *var) {
   1.329 +        if (var->location() == Variable::STACK) {
   1.330 +            getlocal(var);
   1.331 +        } else {
   1.332 +            assert(var->location() == Variable::PARAMETER);
   1.333 +            getarg(var);
   1.334 +        }
   1.335 +    }
   1.336 +    void set(Variable *var) {
   1.337 +        assert(!var->type()->isReference());
   1.338 +        if (var->location() == Variable::STACK) {
   1.339 +            setlocal(var);
   1.340 +        } else {
   1.341 +            assert(var->location() == Variable::PARAMETER);
   1.342 +            setarg(var);
   1.343 +        }
   1.344      }
   1.345  };
   1.346