Add an instruction abstraction and visitor.

Change-Id: I5dc935831471296b6db1affef6e7ddcdddc82dde
diff --git a/Android.aexec.host.mk b/Android.aexec.host.mk
index 20cc1ee..44ecf77 100644
--- a/Android.aexec.host.mk
+++ b/Android.aexec.host.mk
@@ -26,7 +26,4 @@
 LOCAL_SHARED_LIBRARIES := \
 	libart
 
-LOCAL_C_INCLUDES += \
-	$(LOCAL_PATH)/src
-
 include $(BUILD_HOST_EXECUTABLE)
diff --git a/Android.aexec.mk b/Android.aexec.mk
index 59dccef..dd5bf58 100644
--- a/Android.aexec.mk
+++ b/Android.aexec.mk
@@ -27,10 +27,9 @@
 	libart \
 	libstlport
 
-LOCAL_C_INCLUDES += \
+LOCAL_C_INCLUDES := \
 	external/stlport/stlport \
 	bionic \
-	bionic/libstdc++/include \
-	$(LOCAL_PATH)/src
+	bionic/libstdc++/include
 
 include $(BUILD_EXECUTABLE)
diff --git a/Android.common.mk b/Android.common.mk
index c4f332f..916a1f9 100644
--- a/Android.common.mk
+++ b/Android.common.mk
@@ -22,6 +22,7 @@
 LIBART_LOCAL_SRC_FILES := \
 	src/art.cc \
 	src/assembler.cc \
+	src/dex_instruction.cc \
 	src/memory_region.cc
 
 ifeq ($(LIBART_TARGET_ARCH),arm)
@@ -34,7 +35,8 @@
 	src/assembler_x86.cc
 endif
 
-TEST_LOCAL_SRC_FILES :=
+TEST_LOCAL_SRC_FILES := \
+	src/dex_instruction_visitor_test.cc
 
 ifeq ($(TEST_TARGET_ARCH),arm)
 TEST_LOCAL_SRC_FILES +=
diff --git a/Android.libart.host.mk b/Android.libart.host.mk
index d0d3c8f..edb6869 100644
--- a/Android.libart.host.mk
+++ b/Android.libart.host.mk
@@ -24,22 +24,20 @@
 include $(LOCAL_PATH)/Android.common.mk
 LOCAL_SRC_FILES := $(LIBART_LOCAL_SRC_FILES)
 
-LOCAL_CFLAGS += \
+LOCAL_CFLAGS := \
 	-g3 \
 	-Wall \
 	-Wextra \
 	-Wno-unused-parameter \
 	-Wstrict-aliasing=2 \
 	-fno-align-jumps \
-	-fstrict-aliasing \
-	-fvisibility=hidden
+	-fstrict-aliasing
 
-LOCAL_C_INCLUDES += \
-	dalvik/libdex \
-	libcore/include \
-	$(LOCAL_PATH)/src
+LOCAL_C_INCLUDES := \
+	dalvik \
+	libcore/include
 
-LOCAL_WHOLE_STATIC_LIBRARIES += \
+LOCAL_WHOLE_STATIC_LIBRARIES := \
 	libcutils \
 	libdex \
 	liblog \
diff --git a/Android.libart.mk b/Android.libart.mk
index c54a6fe..6e86e98 100644
--- a/Android.libart.mk
+++ b/Android.libart.mk
@@ -24,31 +24,37 @@
 include $(LOCAL_PATH)/Android.common.mk
 LOCAL_SRC_FILES := $(LIBART_LOCAL_SRC_FILES)
 
-LOCAL_CFLAGS += \
+LOCAL_CFLAGS := \
+	-g3
 	-Wall \
 	-Wextra \
 	-Wno-unused-parameter \
 	-Wstrict-aliasing=2 \
 	-fno-align-jumps \
-	-fstrict-aliasing \
-	-fvisibility=hidden
+	-fstrict-aliasing
 
 ifeq ($(TARGET_ARCH),arm)
-	LOCAL_CFLAGS +=
+LOCAL_CFLAGS +=
 endif
 
 ifeq ($(TARGET_ARCH),x86)
-	LOCAL_CFLAGS +=
+LOCAL_CFLAGS +=
 endif
 
-LOCAL_C_INCLUDES += \
+LOCAL_C_INCLUDES := \
 	external/stlport/stlport \
 	bionic/ \
 	bionic/libstdc++/include \
-	dalvik/libdex \
-	libcore/include \
-	$(LOCAL_PATH)/src
+	dalvik \
+	libcore/include
 
-LOCAL_SHARED_LIBRARIES += libstlport
+LOCAL_STATIC_LIBRARIES := \
+	libdex
+
+LOCAL_SHARED_LIBRARIES := \
+	libstlport \
+	liblog \
+	libcutils \
+	libz
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/Android.test.host.mk b/Android.test.host.mk
index 608fde1..2d7fedd 100644
--- a/Android.test.host.mk
+++ b/Android.test.host.mk
@@ -19,6 +19,7 @@
 
 local_module_tags := eng tests
 
+TEST_TARGET_ARCH := $(HOST_ARCH)
 include $(LOCAL_PATH)/Android.common.mk
 local_cpp_extension := $(LOCAL_CPP_EXTENSION)
 
@@ -26,8 +27,8 @@
 	libart
 
 local_c_includes := \
-	external/gtest/include \
-	$(LOCAL_PATH)/src
+	dalvik \
+	external/gtest/include
 
 local_whole_static_libraries := \
 	libgtest_host \
diff --git a/src/dex_instruction.cc b/src/dex_instruction.cc
new file mode 100644
index 0000000..83ebddc
--- /dev/null
+++ b/src/dex_instruction.cc
@@ -0,0 +1,27 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "libdex/InstrUtils.h"
+#undef LOG
+#undef LOG_FATAL
+
+#include "src/dex_instruction.h"
+
+namespace art {
+
+size_t Instruction::Size() {
+  const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
+  return dexGetWidthFromInstruction(insns) * sizeof(uint16_t);
+}
+
+Instruction::Code Instruction::Opcode() {
+  const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
+  return (Instruction::Code)dexOpcodeFromCodeUnit(*insns);
+}
+
+const Instruction* Instruction::Next() {
+  size_t current_size = Size();
+  const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
+  return reinterpret_cast<const Instruction*>(ptr + current_size);
+}
+
+}  // namespace art
diff --git a/src/dex_instruction.h b/src/dex_instruction.h
new file mode 100644
index 0000000..2c1c15f
--- /dev/null
+++ b/src/dex_instruction.h
@@ -0,0 +1,261 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_DEX_INSTRUCTION_H_
+#define ART_SRC_DEX_INSTRUCTION_H_
+
+#include "src/globals.h"
+#include "src/logging.h"
+#include "src/macros.h"
+
+namespace art {
+
+#define DEX_INSTRUCTION_LIST(V) \
+  V(NOP, 0x0) \
+  V(MOVE, 0x1) \
+  V(MOVE_FROM16, 0x2) \
+  V(MOVE_16, 0x3) \
+  V(MOVE_WIDE, 0x4) \
+  V(MOVE_WIDE_FROM16, 0x5) \
+  V(MOVE_WIDE_16, 0x6) \
+  V(MOVE_OBJECT, 0x7) \
+  V(MOVE_OBJECT_FROM16, 0x8) \
+  V(MOVE_OBJECT_16, 0x9) \
+  V(MOVE_RESULT, 0xA) \
+  V(MOVE_RESULT_WIDE, 0xB) \
+  V(MOVE_RESULT_OBJECT, 0xC) \
+  V(MOVE_EXCEPTION, 0xD) \
+  V(RETURN_VOID, 0xE) \
+  V(RETURN, 0xF) \
+  V(RETURN_WIDE, 0x10) \
+  V(RETURN_OBJECT, 0x11) \
+  V(CONST_4, 0x12) \
+  V(CONST_16, 0x13) \
+  V(CONST, 0x14) \
+  V(CONST_HIGH16, 0x15) \
+  V(CONST_WIDE_16, 0x16) \
+  V(CONST_WIDE_32, 0x17) \
+  V(CONST_WIDE, 0x18) \
+  V(CONST_WIDE_HIGH16, 0x19) \
+  V(CONST_STRING, 0x1A) \
+  V(CONST_STRING_JUMBO, 0x1B) \
+  V(CONST_CLASS, 0x1C) \
+  V(MONITOR_ENTER, 0x1D) \
+  V(MONITOR_EXIT, 0x1E) \
+  V(CHECK_CAST, 0x1F) \
+  V(INSTANCE_OF, 0x20) \
+  V(ARRAY_LENGTH, 0x21) \
+  V(NEW_INSTANCE, 0x22) \
+  V(NEW_ARRAY, 0x23) \
+  V(FILLED_NEW_ARRAY, 0x24) \
+  V(FILLED_NEW_ARRAY_RANGE, 0x25) \
+  V(FILL_ARRAY_DATA, 0x26) \
+  V(THROW, 0x27) \
+  V(GOTO, 0x28) \
+  V(GOTO_16, 0x29) \
+  V(GOTO_32, 0x2A) \
+  V(PACKED_SWITCH, 0x2B) \
+  V(SPARSE_SWITCH, 0x2C) \
+  V(CMPL_FLOAT, 0x2D) \
+  V(CMPG_FLOAT, 0x2E) \
+  V(CMPL_DOUBLE, 0x2F) \
+  V(CMPG_DOUBLE, 0x30) \
+  V(CMP_LONG, 0x31) \
+  V(IF_EQ, 0x32) \
+  V(IF_NE, 0x33) \
+  V(IF_LT, 0x34) \
+  V(IF_GE, 0x35) \
+  V(IF_GT, 0x36) \
+  V(IF_LE, 0x37) \
+  V(IF_EQZ, 0x38) \
+  V(IF_NEZ, 0x39) \
+  V(IF_LTZ, 0x3A) \
+  V(IF_GEZ, 0x3B) \
+  V(IF_GTZ, 0x3C) \
+  V(IF_LEZ, 0x3D) \
+  V(AGET, 0x44) \
+  V(AGET_WIDE, 0x45) \
+  V(AGET_OBJECT, 0x46) \
+  V(AGET_BOOLEAN, 0x47) \
+  V(AGET_BYTE, 0x48) \
+  V(AGET_CHAR, 0x49) \
+  V(AGET_SHORT, 0x4A) \
+  V(APUT, 0x4B) \
+  V(APUT_WIDE, 0x4C) \
+  V(APUT_OBJECT, 0x4D) \
+  V(APUT_BOOLEAN, 0x4E) \
+  V(APUT_BYTE, 0x4F) \
+  V(APUT_CHAR, 0x50) \
+  V(APUT_SHORT, 0x51) \
+  V(IGET, 0x52) \
+  V(IGET_WIDE, 0x53) \
+  V(IGET_OBJECT, 0x54) \
+  V(IGET_BOOLEAN, 0x55) \
+  V(IGET_BYTE, 0x56) \
+  V(IGET_CHAR, 0x57) \
+  V(IGET_SHORT, 0x58) \
+  V(IPUT, 0x59) \
+  V(IPUT_WIDE, 0x5A) \
+  V(IPUT_OBJECT, 0x5B) \
+  V(IPUT_BOOLEAN, 0x5C) \
+  V(IPUT_BYTE, 0x5D) \
+  V(IPUT_CHAR, 0x5E) \
+  V(IPUT_SHORT, 0x5F) \
+  V(SGET, 0x60) \
+  V(SGET_WIDE, 0x61) \
+  V(SGET_OBJECT, 0x62) \
+  V(SGET_BOOLEAN, 0x63) \
+  V(SGET_BYTE, 0x64) \
+  V(SGET_CHAR, 0x65) \
+  V(SGET_SHORT, 0x66) \
+  V(SPUT, 0x67) \
+  V(SPUT_WIDE, 0x68) \
+  V(SPUT_OBJECT, 0x69) \
+  V(SPUT_BOOLEAN, 0x6A) \
+  V(SPUT_BYTE, 0x6B) \
+  V(SPUT_CHAR, 0x6C) \
+  V(SPUT_SHORT, 0x6D) \
+  V(INVOKE_VIRTUAL, 0x6E) \
+  V(INVOKE_SUPER, 0x6F) \
+  V(INVOKE_DIRECT, 0x70) \
+  V(INVOKE_STATIC, 0x71) \
+  V(INVOKE_INTERFACE, 0x72) \
+  V(INVOKE_VIRTUAL_RANGE, 0x74) \
+  V(INVOKE_SUPER_RANGE, 0x75) \
+  V(INVOKE_DIRECT_RANGE, 0x76) \
+  V(INVOKE_STATIC_RANGE, 0x77) \
+  V(INVOKE_INTERFACE_RANGE, 0x78) \
+  V(NEG_INT, 0x7B) \
+  V(NOT_INT, 0x7C) \
+  V(NEG_LONG, 0x7D) \
+  V(NOT_LONG, 0x7E) \
+  V(NEG_FLOAT, 0x7F) \
+  V(NEG_DOUBLE, 0x80) \
+  V(INT_TO_LONG, 0x81) \
+  V(INT_TO_FLOAT, 0x82) \
+  V(INT_TO_DOUBLE, 0x83) \
+  V(LONG_TO_INT, 0x84) \
+  V(LONG_TO_FLOAT, 0x85) \
+  V(LONG_TO_DOUBLE, 0x86) \
+  V(FLOAT_TO_INT, 0x87) \
+  V(FLOAT_TO_LONG, 0x88) \
+  V(FLOAT_TO_DOUBLE, 0x89) \
+  V(DOUBLE_TO_INT, 0x8A) \
+  V(DOUBLE_TO_LONG, 0x8B) \
+  V(DOUBLE_TO_FLOAT, 0x8C) \
+  V(INT_TO_BYTE, 0x8D) \
+  V(INT_TO_CHAR, 0x8E) \
+  V(INT_TO_SHORT, 0x8F) \
+  V(ADD_INT, 0x90) \
+  V(SUB_INT, 0x91) \
+  V(MUL_INT, 0x92) \
+  V(DIV_INT, 0x93) \
+  V(REM_INT, 0x94) \
+  V(AND_INT, 0x95) \
+  V(OR_INT, 0x96) \
+  V(XOR_INT, 0x97) \
+  V(SHL_INT, 0x98) \
+  V(SHR_INT, 0x99) \
+  V(USHR_INT, 0x9A) \
+  V(ADD_LONG, 0x9B) \
+  V(SUB_LONG, 0x9C) \
+  V(MUL_LONG, 0x9D) \
+  V(DIV_LONG, 0x9E) \
+  V(REM_LONG, 0x9F) \
+  V(AND_LONG, 0xA0) \
+  V(OR_LONG, 0xA1) \
+  V(XOR_LONG, 0xA2) \
+  V(SHL_LONG, 0xA3) \
+  V(SHR_LONG, 0xA4) \
+  V(USHR_LONG, 0xA5) \
+  V(ADD_FLOAT, 0xA6) \
+  V(SUB_FLOAT, 0xA7) \
+  V(MUL_FLOAT, 0xA8) \
+  V(DIV_FLOAT, 0xA9) \
+  V(REM_FLOAT, 0xAA) \
+  V(ADD_DOUBLE, 0xAB) \
+  V(SUB_DOUBLE, 0xAC) \
+  V(MUL_DOUBLE, 0xAD) \
+  V(DIV_DOUBLE, 0xAE) \
+  V(REM_DOUBLE, 0xAF) \
+  V(ADD_INT_2ADDR, 0xB0) \
+  V(SUB_INT_2ADDR, 0xB1) \
+  V(MUL_INT_2ADDR, 0xB2) \
+  V(DIV_INT_2ADDR, 0xB3) \
+  V(REM_INT_2ADDR, 0xB4) \
+  V(AND_INT_2ADDR, 0xB5) \
+  V(OR_INT_2ADDR, 0xB6) \
+  V(XOR_INT_2ADDR, 0xB7) \
+  V(SHL_INT_2ADDR, 0xB8) \
+  V(SHR_INT_2ADDR, 0xB9) \
+  V(USHR_INT_2ADDR, 0xBA) \
+  V(ADD_LONG_2ADDR, 0xBB) \
+  V(SUB_LONG_2ADDR, 0xBC) \
+  V(MUL_LONG_2ADDR, 0xBD) \
+  V(DIV_LONG_2ADDR, 0xBE) \
+  V(REM_LONG_2ADDR, 0xBF) \
+  V(AND_LONG_2ADDR, 0xC0) \
+  V(OR_LONG_2ADDR, 0xC1) \
+  V(XOR_LONG_2ADDR, 0xC2) \
+  V(SHL_LONG_2ADDR, 0xC3) \
+  V(SHR_LONG_2ADDR, 0xC4) \
+  V(USHR_LONG_2ADDR, 0xC5) \
+  V(ADD_FLOAT_2ADDR, 0xC6) \
+  V(SUB_FLOAT_2ADDR, 0xC7) \
+  V(MUL_FLOAT_2ADDR, 0xC8) \
+  V(DIV_FLOAT_2ADDR, 0xC9) \
+  V(REM_FLOAT_2ADDR, 0xCA) \
+  V(ADD_DOUBLE_2ADDR, 0xCB) \
+  V(SUB_DOUBLE_2ADDR, 0xCC) \
+  V(MUL_DOUBLE_2ADDR, 0xCD) \
+  V(DIV_DOUBLE_2ADDR, 0xCE) \
+  V(REM_DOUBLE_2ADDR, 0xCF) \
+  V(ADD_INT_LIT16, 0xD0) \
+  V(RSUB_INT, 0xD1) \
+  V(MUL_INT_LIT16, 0xD2) \
+  V(DIV_INT_LIT16, 0xD3) \
+  V(REM_INT_LIT16, 0xD4) \
+  V(AND_INT_LIT16, 0xD5) \
+  V(OR_INT_LIT16, 0xD6) \
+  V(XOR_INT_LIT16, 0xD7) \
+  V(ADD_INT_LIT8, 0xD8) \
+  V(RSUB_INT_LIT8, 0xD9) \
+  V(MUL_INT_LIT8, 0xDA) \
+  V(DIV_INT_LIT8, 0xDB) \
+  V(REM_INT_LIT8, 0xDC) \
+  V(AND_INT_LIT8, 0xDD) \
+  V(OR_INT_LIT8, 0xDE) \
+  V(XOR_INT_LIT8, 0xDF) \
+  V(SHL_INT_LIT8, 0xE0) \
+  V(SHR_INT_LIT8, 0xE1) \
+  V(USHR_INT_LIT8, 0xE2)
+
+class Instruction {
+ public:
+#define INSTRUCTION_ENUM(cname, opcode) cname = opcode,
+  enum Code {
+    DEX_INSTRUCTION_LIST(INSTRUCTION_ENUM)
+  };
+#undef INSTRUCTION_ENUM
+
+  // Returns the size in bytes of this instruction.
+  size_t Size();
+
+  // Returns a pointer to the next instruction in the stream.
+  const Instruction* Next();
+
+  // Returns the opcode field of the instruction.
+  Code Opcode();
+
+  // Reads an instruction out of the stream at the specified address.
+  static Instruction* At(byte* code) {
+    CHECK(code != NULL);
+    return reinterpret_cast<Instruction*>(code);
+  }
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction);
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_DEX_INSTRUCTION_H_
diff --git a/src/dex_instruction_visitor.h b/src/dex_instruction_visitor.h
new file mode 100644
index 0000000..1a8325c
--- /dev/null
+++ b/src/dex_instruction_visitor.h
@@ -0,0 +1,53 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_DEX_INSTRUCTION_VISITOR_H_
+#define ART_SRC_DEX_INSTRUCTION_VISITOR_H_
+
+#include "src/dex_instruction.h"
+#include "src/macros.h"
+
+namespace art {
+
+template<typename T>
+class DexInstructionVisitor {
+ public:
+  void Visit(uint16_t* code, size_t size) {
+    T* derived = static_cast<T*>(this);
+    byte* ptr = reinterpret_cast<byte*>(code);
+    byte* end = ptr + size;
+    while (ptr != end) {
+      Instruction* inst = Instruction::At(ptr);
+      switch (inst->Opcode()) {
+#define INSTRUCTION_CASE(cname, value)             \
+        case Instruction::cname: {                 \
+          derived->Do_ ## cname(inst);             \
+          break;                                   \
+        }
+        DEX_INSTRUCTION_LIST(INSTRUCTION_CASE)
+#undef INSTRUCTION_CASE
+        default:
+          CHECK(true);
+      }
+      ptr += inst->Size();
+    }
+  }
+
+ private:
+  // Specific handlers for each instruction.
+#define INSTRUCTION_VISITOR(cname, value) \
+  void Do_ ## cname(Instruction* inst) {  \
+    T* derived = static_cast<T*>(this);   \
+    derived->Do_Default(inst);            \
+  };
+  DEX_INSTRUCTION_LIST(INSTRUCTION_VISITOR);
+#undef INSTRUCTION_VISITOR
+
+  // The default instruction handler.
+  void Do_Default(Instruction* inst) {
+    return;
+  }
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_DEX_INSTRUCTION_VISITOR_H_
diff --git a/src/dex_instruction_visitor_test.cc b/src/dex_instruction_visitor_test.cc
new file mode 100644
index 0000000..239e1eb
--- /dev/null
+++ b/src/dex_instruction_visitor_test.cc
@@ -0,0 +1,54 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "src/dex_instruction_visitor.h"
+
+#include <iostream>
+#include "gtest/gtest.h"
+
+namespace art {
+
+class TestVisitor : public DexInstructionVisitor<TestVisitor> {};
+
+TEST(Instruction, Init) {
+  TestVisitor visitor;
+}
+
+class CountVisitor : public DexInstructionVisitor<CountVisitor> {
+ public:
+  int count_;
+
+  CountVisitor() : count_(0) {}
+
+  void Do_Default(Instruction* inst) {
+    ++count_;
+  }
+};
+
+TEST(Instruction, Count) {
+  CountVisitor v0;
+  uint16_t c0[] = {};
+  v0.Visit(c0, sizeof(c0));
+  EXPECT_EQ(0, v0.count_);
+
+  CountVisitor v1;
+  uint16_t c1[] = { 0 };
+  v1.Visit(c1, sizeof(c1));
+  EXPECT_EQ(1, v1.count_);
+
+  CountVisitor v2;
+  uint16_t c2[] = { 0, 0 };
+  v2.Visit(c2, sizeof(c2));
+  EXPECT_EQ(2, v2.count_);
+
+  CountVisitor v3;
+  uint16_t c3[] = { 0, 0, 0, };
+  v3.Visit(c3, sizeof(c3));
+  EXPECT_EQ(3, v3.count_);
+
+  CountVisitor v4;
+  uint16_t c4[] = { 0, 0, 0, 0  };
+  v4.Visit(c4, sizeof(c4));
+  EXPECT_EQ(4, v4.count_);
+}
+
+}  // namespace art
diff --git a/src/macros.h b/src/macros.h
index 078628f..047a95e 100644
--- a/src/macros.h
+++ b/src/macros.h
@@ -14,6 +14,8 @@
 #ifndef ART_SRC_MACROS_H_
 #define ART_SRC_MACROS_H_
 
+#include <stddef.h>  // for size_t
+
 // The COMPILE_ASSERT macro can be used to verify that a compile time
 // expression is true. For example, you could use it to verify the
 // size of a static array: