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