[vmkit-commits] [vmkit] r180460 - Some compilers like Scala and Kotlin produce unreachable code. Vmkit cannot handle this.

Peter Senna Tschudin peter.senna at gmail.com
Thu Apr 25 10:13:46 PDT 2013


Author: peter.senna
Date: Thu Apr 25 12:12:15 2013
New Revision: 180460

URL: http://llvm.org/viewvc/llvm-project?rev=180460&view=rev
Log:
Some compilers like Scala and Kotlin produce unreachable code. Vmkit cannot handle this.
(cherry picked from commit 37f7ad9b8ae26b3cd936f27b1b960fa4997543fc)

Modified:
    vmkit/trunk/lib/j3/Compiler/JavaJIT.cpp
    vmkit/trunk/lib/j3/Compiler/JavaJIT.h
    vmkit/trunk/lib/j3/Compiler/JavaJITOpcodes.cpp

Modified: vmkit/trunk/lib/j3/Compiler/JavaJIT.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/lib/j3/Compiler/JavaJIT.cpp?rev=180460&r1=180459&r2=180460&view=diff
==============================================================================
--- vmkit/trunk/lib/j3/Compiler/JavaJIT.cpp (original)
+++ vmkit/trunk/lib/j3/Compiler/JavaJIT.cpp Thu Apr 25 12:12:15 2013
@@ -1178,8 +1178,11 @@ llvm::Function* JavaJIT::javaCompile() {
   }
 
   reader.cursor = start;
+  findUnreachableCode(reader, codeLen);
+
+  reader.cursor = start;
   compileOpcodes(reader, codeLen);
-  
+
   // This isn't a real requirement, although javac-produced bytcode does
   // seem to adhere to it.  However jython and similar (clojure, etc) don't
   // always create bytecode that matches this, and AFAICT rejecting the
@@ -2490,6 +2493,8 @@ unsigned JavaJIT::readExceptionTable(Rea
     ex->endpc     = reader.readU2();
     ex->handlerpc = reader.readU2();
 
+    opcodeInfos[ex->handlerpc].isReachable = true;
+
     ex->catche = reader.readU2();
 
     if (ex->catche) {
@@ -2512,6 +2517,7 @@ unsigned JavaJIT::readExceptionTable(Rea
     for (uint16 i = ex->startpc; i < ex->endpc; ++i) {
       if (opcodeInfos[i].exceptionBlock == endExceptionBlock) {
         opcodeInfos[i].exceptionBlock = ex->tester;
+        //opcodeInfos[i].handlerPC = ex->handlerpc;
       }
     }
 

Modified: vmkit/trunk/lib/j3/Compiler/JavaJIT.h
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/lib/j3/Compiler/JavaJIT.h?rev=180460&r1=180459&r2=180460&view=diff
==============================================================================
--- vmkit/trunk/lib/j3/Compiler/JavaJIT.h (original)
+++ vmkit/trunk/lib/j3/Compiler/JavaJIT.h Thu Apr 25 12:12:15 2013
@@ -68,6 +68,13 @@ struct Opinfo {
 
   /// backEdge - If this block is a back edge.
   bool backEdge;
+
+
+  // isReachable - Indicate if the opcode is Reachable
+  bool isReachable;
+
+  // index of its handler, 0 if none
+  uint16 handlerPC;
 };
 
 /// JavaJIT - The compilation engine of J3. Parses the bycode and returns
@@ -251,6 +258,10 @@ private:
   /// loadConstant - Load a constant from the _ldc bytecode.
   void loadConstant(uint16 index);
 
+  /// mark every opcode as reachable or unreachable
+  void findUnreachableCode(Reader& reader, uint32 codeLen);
+
+
 //===------------------------- Runtime exceptions -------------------------===//
   
   /// JITVerifyNull - Insert a null pointer check in the LLVM code.
@@ -357,6 +368,11 @@ private:
       return new llvm::LoadInst(longStack[currentStackIndex - 1], "", false,
                                 currentBlock);
     } else {
+      llvm::Value* ttt = objectStack[currentStackIndex - 1];
+      if (((unsigned int)ttt) < 0xFFF) {
+
+    	  printf("Why in method %s.%s???\n" , UTF8Buffer(compilingClass->name).cString(), UTF8Buffer(compilingMethod->name).cString() );
+      }
       return new llvm::LoadInst(objectStack[currentStackIndex - 1], "",
                                 false, currentBlock);
     }

Modified: vmkit/trunk/lib/j3/Compiler/JavaJITOpcodes.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/lib/j3/Compiler/JavaJITOpcodes.cpp?rev=180460&r1=180459&r2=180460&view=diff
==============================================================================
--- vmkit/trunk/lib/j3/Compiler/JavaJITOpcodes.cpp (original)
+++ vmkit/trunk/lib/j3/Compiler/JavaJITOpcodes.cpp Thu Apr 25 12:12:15 2013
@@ -98,13 +98,283 @@ static inline uint32 WCALC(uint32 n, boo
   }
 }
 
+#include <queue>
+
+static uint8 sum [] = {
+		2,
+		3,
+		2,
+		3,
+		3,
+		2,
+		2,
+		2,
+		2,
+		2
+};
+
+static uint8 sum2 [] = {
+		3,
+		3,
+		3,
+		3,
+		3,
+		3,
+		3,
+		5,
+		5,
+		3,
+		2,
+		3,
+		1,
+		1,
+		3,
+		3,
+		1,
+		1
+};
+
+void JavaJIT::findUnreachableCode(Reader& reader, uint32 codeLen) {
+	std::queue<uint32> queue;
+	queue.push(0);
+	opcodeInfos[0].isReachable = true;
+
+	for (int i = 0; i < codeLen; ++i) {
+		if (opcodeInfos[i].isReachable)
+			queue.push(i);
+	}
+
+	uint32 start = reader.cursor;
+	while (queue.size()) {
+		// pick one index from the queue
+		uint32 i_opcode = queue.front();
+		queue.pop();
+		// read the opcode at this position
+		reader.cursor = start + i_opcode;
+		uint8 bytecode = reader.readU1();
+		// if the opcode is a section which has a handle other than the endBlockHandler then we must add the initial instruction of that handler to the queue
+		if (opcodeInfos[i_opcode].handlerPC) {
+			uint16 pc = opcodeInfos[i_opcode].handlerPC;
+			if (pc < codeLen && !opcodeInfos[pc].isReachable) {
+				opcodeInfos[pc].isReachable = true;
+				queue.push(pc);
+			}
+		}
+		//
+		// if the opcode does not involve a branch then mark the next instruction as reachable (DONE)
+		// if the opcode is an unconditional branch then mark the target as reachable (DONE)
+		// if the opcode is a conditional branch then mark the target and the next instruction as reachable (DONE)
+		// if it is a ret instruction then I don't know what to do.
+		// if it is a jsr instruction then mark the target as reachable (DONE)
+		// if it is tableswitch instruction then mark all cases as reachable (DONE)
+		// if it is lookupswitch instruction then mark all cases as reachable (DONE)
+		// wide instruction (DONE)
+		if (bytecode < IFEQ) {
+			uint32 next_index = 1;
+			if (bytecode >= BIPUSH && bytecode <= ALOAD)
+				next_index = sum[bytecode - BIPUSH];
+			else if (bytecode >= ISTORE && bytecode <= ASTORE)
+				next_index = 2;
+			else if (bytecode == IINC)
+				next_index = 3;
+			next_index += i_opcode;
+			if (next_index < codeLen && !opcodeInfos[next_index].isReachable) {
+				opcodeInfos[next_index].isReachable = true;
+				queue.push(next_index);
+			}
+		}
+		else if (bytecode >= IFEQ && bytecode <= IF_ACMPNE) {
+			uint32 next_index = 3 + i_opcode;
+			if (next_index < codeLen && !opcodeInfos[next_index].isReachable) {
+				opcodeInfos[next_index].isReachable = true;
+				queue.push(next_index);
+			}
+			uint16 b1 = reader.readU1();
+			uint8 b2 = reader.readU1();
+			sint16 step = (b1 << 8) | b2;
+			next_index = i_opcode + step;
+			if (next_index < codeLen && !opcodeInfos[next_index].isReachable) {
+				opcodeInfos[next_index].isReachable = true;
+				queue.push(next_index);
+			}
+		}
+		else if (bytecode >= GETSTATIC && bytecode <= MONITOREXIT && bytecode != ATHROW) {
+			uint32 next_index = sum2[bytecode - GETSTATIC] + i_opcode;
+			if (next_index < codeLen && !opcodeInfos[next_index].isReachable) {
+				opcodeInfos[next_index].isReachable = true;
+				queue.push(next_index);
+			}
+		}
+		else {
+			uint32 x;
+			sint32 defaultIndex,lowIndex, highIndex;
+			uint32 next_index = codeLen;
+			sint16 step;
+			sint32 step32;
+			uint16 b1;
+			uint8 b2,b3,b4;
+			switch (bytecode) {
+				case GOTO:
+					b1 = reader.readU1();
+					b2 = reader.readU1();
+					step = (b1 << 8) | b2;
+					next_index = i_opcode + step;
+					break;
+				case GOTO_W:
+					next_index = reader.readU1();
+					b2 = reader.readU1();
+					b3 = reader.readU1();
+					b4 = reader.readU1();
+					step32 =  (next_index << 24) | (b2 << 16) | (b3 << 8) | b4;
+					next_index = step32 + i_opcode;
+					break;
+				case MULTIANEWARRAY:
+					next_index = i_opcode + 4;
+					break;
+				case IFNULL:
+				case IFNONNULL:
+				case JSR:
+					next_index = i_opcode + 3;
+					if (next_index < codeLen && !opcodeInfos[next_index].isReachable) {
+						opcodeInfos[next_index].isReachable = true;
+						queue.push(next_index);
+					}
+					b1 = reader.readU1();
+					b2 = reader.readU1();
+					step = (b1 << 8) | b2;
+					next_index = i_opcode + step;
+					break;
+				case JSR_W:
+					next_index = i_opcode + 5;
+					if (next_index < codeLen && !opcodeInfos[next_index].isReachable) {
+						opcodeInfos[next_index].isReachable = true;
+						queue.push(next_index);
+					}
+					next_index = reader.readU1();
+					b2 = reader.readU1();
+					b3 = reader.readU1();
+					b4 = reader.readU1();
+					step32 =  (next_index << 24) | (b2 << 16) | (b3 << 8) | b4;
+					next_index = step32 + i_opcode;
+					break;
+				case WIDE:
+					if (i_opcode + 1 < codeLen && !opcodeInfos[i_opcode + 1].isReachable) {
+						opcodeInfos[i_opcode + 1].isReachable = true;
+						queue.push(i_opcode + 1);
+					}
+					b2 = reader.readU1();
+					next_index = i_opcode + ((b2 == IINC)?6:4);
+					break;
+				case TABLESWITCH:
+					//break;
+					x = i_opcode & 0x03; // remainder of division by 4
+					reader.cursor = start + 4 - x + i_opcode;
+					// default
+					defaultIndex = reader.readU1();
+					b2 = reader.readU1();
+					b3 = reader.readU1();
+					b4 = reader.readU1();
+					step32 =  (defaultIndex << 24) | (b2 << 16) | (b3 << 8) | b4;
+					defaultIndex = step32 + i_opcode;
+					if (defaultIndex < codeLen && !opcodeInfos[defaultIndex].isReachable) {
+						opcodeInfos[defaultIndex].isReachable = true;
+						queue.push(defaultIndex);
+					}
+					// low
+					lowIndex = reader.readU1();
+					b2 = reader.readU1();
+					b3 = reader.readU1();
+					b4 = reader.readU1();
+					step32 =  (lowIndex << 24) | (b2 << 16) | (b3 << 8) | b4;
+					lowIndex = step32 + i_opcode;
+					// high
+					highIndex = reader.readU1();
+					b2 = reader.readU1();
+					b3 = reader.readU1();
+					b4 = reader.readU1();
+					step32 =  (highIndex << 24) | (b2 << 16) | (b3 << 8) | b4;
+					highIndex = step32 + i_opcode;
+					// all options
+					for (int i = 0 ; i < highIndex - lowIndex + 1 ; i++) {
+						next_index = reader.readU1();
+						b2 = reader.readU1();
+						b3 = reader.readU1();
+						b4 = reader.readU1();
+						step32 =  (next_index << 24) | (b2 << 16) | (b3 << 8) | b4;
+						next_index = step32 + i_opcode;
+						if (next_index < codeLen && !opcodeInfos[next_index].isReachable) {
+							opcodeInfos[next_index].isReachable = true;
+							queue.push(next_index);
+						}
+					}
+					next_index = codeLen;
+					break;
+				case LOOKUPSWITCH:
+					//break;
+					x = i_opcode & 0x03; // remainder of division by 4
+					reader.cursor = start + 4 - x + i_opcode;
+					// default
+					defaultIndex = reader.readU1();
+					b2 = reader.readU1();
+					b3 = reader.readU1();
+					b4 = reader.readU1();
+					step32 =  (defaultIndex << 24) | (b2 << 16) | (b3 << 8) | b4;
+					defaultIndex = step32 + i_opcode;
+					if (defaultIndex < codeLen && !opcodeInfos[defaultIndex].isReachable) {
+						opcodeInfos[defaultIndex].isReachable = true;
+						queue.push(defaultIndex);
+					}
+					// npairs
+					lowIndex = reader.readU1();
+					b2 = reader.readU1();
+					b3 = reader.readU1();
+					b4 = reader.readU1();
+					step32 =  (lowIndex << 24) | (b2 << 16) | (b3 << 8) | b4;
+					lowIndex = step32 + i_opcode;
+					// all options
+					for (int i = 0 ; i < lowIndex ; i++) {
+						reader.cursor += 4; // skipping match
+						// offset
+						next_index = reader.readU1();
+						b2 = reader.readU1();
+						b3 = reader.readU1();
+						b4 = reader.readU1();
+						step32 =  (next_index << 24) | (b2 << 16) | (b3 << 8) | b4;
+						next_index = step32 + i_opcode;
+						if (next_index < codeLen && !opcodeInfos[next_index].isReachable) {
+							opcodeInfos[next_index].isReachable = true;
+							queue.push(next_index);
+						}
+					}
+					next_index = codeLen;
+					break;
+				default:
+					break;
+			}
+			if (next_index < codeLen && !opcodeInfos[next_index].isReachable) {
+				opcodeInfos[next_index].isReachable = true;
+				queue.push(next_index);
+			}
+		}
+	} // end while
+}
+
 void JavaJIT::compileOpcodes(Reader& reader, uint32 codeLength) {
   bool wide = false;
   uint32 jsrIndex = 0;
   uint32 start = reader.cursor;
+
+  if (!opcodeInfos[0].isReachable) {
+	  findUnreachableCode(reader, codeLength);
+	  reader.cursor = start;
+  }
+
   vmkit::ThreadAllocator allocator;
   for(uint32 i = 0; i < codeLength; ++i) {
-    reader.cursor = start + i;
+	if (!opcodeInfos[i].isReachable && !opcodeInfos[i].handler) {
+		continue;
+	}
+	reader.cursor = start + i;
     uint8 bytecode = reader.readU1();
     
     PRINT_DEBUG(JNJVM_COMPILE, 1, DARK_BLUE, "\t[at %5d] %-5d ", i,
@@ -127,9 +397,9 @@ void JavaJIT::compileOpcodes(Reader& rea
         	  //PHINode* node = PHINode::Create(obj->getType(), 0, "jaja", opinfo->newBlock);
         	  //node->addIncoming(obj, currentBlock);
         	  // if we were in a handler and now we are in a new handler we simulate a throw
-        	  llvm::Value* arg = pop();
-        	  throwException(arg);
-        	  b = true;
+			  llvm::Value* arg = pop();
+			  throwException(arg);
+			  b = true;
         	  // Original Code
         	  //assert(node && "Handler marlformed");
           }





More information about the vmkit-commits mailing list