Add dex_lang as common frontend to lir and LLVM. dex_lang + bc2lir =
Greenland

First commit of Greenland compiler: It's working in the sense of oat
tests. E.g., mm test-art-host-oat-Fibonacci. It shows the correct
bitcode before lir.

Change-Id: I91cbb02188325eb1fa605ed71ec7108fd2b0dbb9
diff --git a/Android.mk b/Android.mk
index 24e28ac..77e1a71 100644
--- a/Android.mk
+++ b/Android.mk
@@ -36,6 +36,9 @@
 ifeq ($(ART_USE_LLVM_COMPILER),true)
 include $(build_path)/Android.libart-compiler-llvm.mk
 endif
+ifeq ($(ART_USE_GREENLAND_COMPILER),true)
+include $(build_path)/Android.libart-compiler-greenland.mk
+endif
 include $(build_path)/Android.executable.mk
 include $(build_path)/Android.oat.mk
 
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 9af92da..33c33af 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -22,7 +22,23 @@
 ART_USE_LLVM_COMPILER := false
 endif
 
-ifeq ($(ART_USE_LLVM_COMPILER),true)
+ifneq ($(wildcard art/USE_GREENLAND_COMPILER),)
+ART_USE_GREENLAND_COMPILER := true
+else
+ART_USE_GREENLAND_COMPILER := false
+endif
+
+ifeq ($(filter-out true,$(ART_USE_LLVM_COMPILER) $(ART_USE_GREENLAND_COMPILER)),)
+$(error Cannot enable art-greenland and art-llvm compiler simultaneously!)
+endif
+
+ifeq ($(filter true,$(ART_USE_LLVM_COMPILER) $(ART_USE_GREENLAND_COMPILER)),true)
+ART_REQUIRE_LLVM := true
+else
+ART_REQUIRE_LLVM := false
+endif
+
+ifeq ($(ART_REQUIRE_LLVM),true)
 LLVM_ROOT_PATH := external/llvm
 include $(LLVM_ROOT_PATH)/llvm.mk
 endif
@@ -209,6 +225,11 @@
 	src/compiler_llvm/runtime_support_llvm.cc
 endif
 
+ifeq ($(ART_USE_GREENLAND_COMPILER),true)
+LIBART_COMMON_SRC_FILES += \
+       src/greenland/inferred_reg_category_map.cc
+endif
+
 LIBART_COMMON_SRC_FILES += \
 	src/oat/runtime/context.cc \
 	src/oat/runtime/support_alloc.cc \
diff --git a/build/Android.executable.mk b/build/Android.executable.mk
index 5f139ee..9305d4d 100644
--- a/build/Android.executable.mk
+++ b/build/Android.executable.mk
@@ -22,6 +22,10 @@
   ART_EXECUTABLES_CFLAGS += -DART_USE_LLVM_COMPILER=1
 endif
 
+ifeq ($(ART_USE_GREENLAND_COMPILER),true)
+  ART_EXECUTABLES_CFLAGS += -DART_USE_GREENLAND_COMPILER=1
+endif
+
 # $(1): executable ("d" will be appended for debug version)
 # $(2): source
 # $(3): target or host
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 3405e7e..63c4b60 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -24,6 +24,10 @@
   ART_TEST_CFLAGS += -DART_USE_LLVM_COMPILER=1
 endif
 
+ifeq ($(ART_USE_GREENLAND_COMPILER),true)
+  ART_TEST_CFLAGS += -DART_USE_GREENLAND_COMPILER=1
+endif
+
 # $(1): target or host
 # $(2): file name
 define build-art-test
diff --git a/build/Android.libart-compiler-greenland.mk b/build/Android.libart-compiler-greenland.mk
new file mode 100644
index 0000000..04eec5e99
--- /dev/null
+++ b/build/Android.libart-compiler-greenland.mk
@@ -0,0 +1,179 @@
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+
+LIBART_COMPILER_GREENLAND_CFLAGS := -DART_USE_GREENLAND_COMPILER=1
+
+LIBART_COMPILER_GREENLAND_SRC_FILES += \
+	src/greenland/dalvik_reg.cc \
+	src/greenland/dex_lang.cc \
+	src/greenland/greenland.cc \
+	src/greenland/lir.cc \
+	src/greenland/lir_function.cc \
+	src/greenland/inferred_reg_category_map.cc \
+	src/greenland/intrinsic_helper.cc \
+	src/greenland/ir_builder.cc \
+	src/greenland/target_codegen_machine.cc \
+	src/greenland/target_lir_emitter.cc \
+	src/greenland/target_registry.cc \
+	src/oat/jni/calling_convention.cc \
+	src/oat/jni/jni_compiler.cc \
+	src/oat/jni/arm/calling_convention_arm.cc \
+	src/oat/jni/x86/calling_convention_x86.cc
+
+LIBART_COMPILER_GREENLAND_ARM_SRC_FILES += \
+  src/greenland/arm/arm_codegen_machine.cc \
+	src/greenland/arm/arm_invoke_stub_compiler.cc
+
+LIBART_COMPILER_GREENLAND_MIPS_SRC_FILES += \
+  src/greenland/mips/mips_codegen_machine.cc \
+  src/greenland/mips/mips_invoke_stub_compiler.cc
+
+LIBART_COMPILER_GREENLAND_X86_SRC_FILES += \
+  src/greenland/x86/x86_codegen_machine.cc \
+  src/greenland/x86/x86_lir_emitter.cc \
+  src/greenland/x86/x86_lir_info.cc \
+  src/greenland/x86/x86_invoke_stub_compiler.cc
+
+# $(1): target or host
+# $(2): ndebug or debug
+define build-libart-compiler-greenland
+  ifneq ($(1),target)
+    ifneq ($(1),host)
+      $$(error expected target or host for argument 1, received $(1))
+    endif
+  endif
+  ifneq ($(2),ndebug)
+    ifneq ($(2),debug)
+      $$(error expected ndebug or debug for argument 2, received $(2))
+    endif
+  endif
+
+  art_target_or_host := $(1)
+  art_ndebug_or_debug := $(2)
+
+  include $(CLEAR_VARS)
+  ifeq ($$(art_target_or_host),target)
+    include external/stlport/libstlport.mk
+  endif
+  LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
+  ifeq ($$(art_ndebug_or_debug),ndebug)
+    LOCAL_MODULE := libart-compiler-greenland
+  else # debug
+    LOCAL_MODULE := libartd-compiler-greenland
+  endif
+
+  LOCAL_MODULE_TAGS := optional
+  LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+
+  LOCAL_SRC_FILES := $(LIBART_COMPILER_GREENLAND_SRC_FILES)
+  LOCAL_CFLAGS := $(LIBART_COMPILER_GREENLAND_CFLAGS)
+  ifeq ($$(art_target_or_host),target)
+    LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
+  else # host
+    LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
+  endif
+
+  LOCAL_C_INCLUDES += $(ART_C_INCLUDES)
+
+  ifeq ($$(art_target_or_host),target)
+    LOCAL_SRC_FILES += \
+      $(LIBART_COMPILER_GREENLAND_ARM_SRC_FILES)
+  else
+    LOCAL_SRC_FILES += \
+      $(LIBART_COMPILER_GREENLAND_ARM_SRC_FILES) \
+      $(LIBART_COMPILER_GREENLAND_MIPS_SRC_FILES) \
+      $(LIBART_COMPILER_GREENLAND_X86_SRC_FILES)
+  endif
+
+  LOCAL_STATIC_LIBRARIES += \
+    libLLVMBitWriter \
+    libLLVMBitReader \
+    libLLVMScalarOpts \
+    libLLVMInstCombine \
+    libLLVMTransformUtils \
+    libLLVMAnalysis \
+    libLLVMTarget \
+    libLLVMCore \
+    libLLVMSupport
+  LOCAL_SHARED_LIBRARIES := liblog libnativehelper
+  ifeq ($$(art_target_or_host),target)
+    LOCAL_SHARED_LIBRARIES += libcutils libstlport libz libdl
+    LOCAL_SHARED_LIBRARIES += libdynamic_annotations # tsan support
+#    LOCAL_SHARED_LIBRARIES += libcorkscrew # native stack trace support
+  else # host
+    LOCAL_STATIC_LIBRARIES += libcutils
+    LOCAL_SHARED_LIBRARIES += libz-host
+    LOCAL_SHARED_LIBRARIES += libdynamic_annotations-host # tsan support
+    LOCAL_LDLIBS := -ldl -lpthread
+    ifeq ($(HOST_OS),linux)
+      LOCAL_LDLIBS += -lrt
+    endif
+  endif
+  ifeq ($$(art_ndebug_or_debug),debug)
+    ifeq ($$(art_target_or_host),target)
+      LOCAL_CFLAGS += $(ART_TARGET_DEBUG_CFLAGS)
+    else # host
+      LOCAL_CFLAGS += $(ART_HOST_DEBUG_CFLAGS)
+    endif
+    LOCAL_SHARED_LIBRARIES += libartd
+  else
+    ifeq ($$(art_target_or_host),target)
+      LOCAL_CFLAGS += $(ART_TARGET_NON_DEBUG_CFLAGS)
+    else # host
+      LOCAL_CFLAGS += $(ART_HOST_NON_DEBUG_CFLAGS)
+    endif
+    LOCAL_SHARED_LIBRARIES += libart
+  endif
+  ifeq ($$(art_target_or_host),target)
+    include $(LLVM_GEN_INTRINSICS_MK)
+    include $(LLVM_DEVICE_BUILD_MK)
+    include $(BUILD_SHARED_LIBRARY)
+  else # host
+    LOCAL_IS_HOST_MODULE := true
+    include $(LLVM_GEN_INTRINSICS_MK)
+    include $(LLVM_HOST_BUILD_MK)
+    include $(BUILD_HOST_SHARED_LIBRARY)
+  endif
+
+  ifeq ($$(art_target_or_host),target)
+    ifeq ($$(art_ndebug_or_debug),debug)
+      $(TARGET_OUT_EXECUTABLES)/dex2oatd: $$(LOCAL_INSTALLED_MODULE)
+    else
+      $(TARGET_OUT_EXECUTABLES)/dex2oat: $$(LOCAL_INSTALLED_MODULE)
+    endif
+  else # host
+    ifeq ($$(art_ndebug_or_debug),debug)
+      $(HOST_OUT_EXECUTABLES)/dex2oatd: $$(LOCAL_INSTALLED_MODULE)
+    else
+      $(HOST_OUT_EXECUTABLES)/dex2oat: $$(LOCAL_INSTALLED_MODULE)
+    endif
+  endif
+
+endef
+
+ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
+  $(eval $(call build-libart-compiler-greenland,target,ndebug))
+endif
+ifeq ($(ART_BUILD_TARGET_DEBUG),true)
+  $(eval $(call build-libart-compiler-greenland,target,debug))
+endif
+ifeq ($(ART_BUILD_HOST_NDEBUG),true)
+  $(eval $(call build-libart-compiler-greenland,host,ndebug))
+endif
+ifeq ($(ART_BUILD_HOST_DEBUG),true)
+  $(eval $(call build-libart-compiler-greenland,host,debug))
+endif
diff --git a/build/Android.libart.mk b/build/Android.libart.mk
index c7a85ef..2683f14 100644
--- a/build/Android.libart.mk
+++ b/build/Android.libart.mk
@@ -19,6 +19,10 @@
   LIBART_CFLAGS += -DART_USE_LLVM_COMPILER=1
 endif
 
+ifeq ($(ART_USE_GREENLAND_COMPILER),true)
+  LIBART_CFLAGS += -DART_USE_GREENLAND_COMPILER=1
+endif
+
 # $(1): target or host
 # $(2): ndebug or debug
 define build-libart
@@ -91,7 +95,10 @@
   LOCAL_C_INCLUDES += $(ART_C_INCLUDES)
   ifeq ($(ART_USE_LLVM_COMPILER),true)
     LOCAL_C_INCLUDES += frameworks/compile/linkloader
-    LOCAL_STATIC_LIBRARIES += librsloader libLLVMSupport
+    LOCAL_STATIC_LIBRARIES += librsloader
+  endif
+  ifeq ($(ART_REQUIRE_LLVM),true)
+    LOCAL_STATIC_LIBRARIES += libLLVMSupport
   endif
   LOCAL_SHARED_LIBRARIES := liblog libnativehelper
   ifeq ($$(art_target_or_host),target)
@@ -108,13 +115,13 @@
     endif
   endif
   ifeq ($$(art_target_or_host),target)
-    ifeq ($(ART_USE_LLVM_COMPILER),true)
+    ifeq ($(ART_REQUIRE_LLVM),true)
       include $(LLVM_GEN_INTRINSICS_MK)
       include $(LLVM_DEVICE_BUILD_MK)
     endif
     include $(BUILD_SHARED_LIBRARY)
   else # host
-    ifeq ($(ART_USE_LLVM_COMPILER),true)
+    ifeq ($(ART_REQUIRE_LLVM),true)
       include $(LLVM_GEN_INTRINSICS_MK)
       include $(LLVM_HOST_BUILD_MK)
     endif
diff --git a/build/Android.oattest.mk b/build/Android.oattest.mk
index 9a215e0..c9540e8 100644
--- a/build/Android.oattest.mk
+++ b/build/Android.oattest.mk
@@ -45,8 +45,9 @@
   include $(BUILD_HOST_JAVA_LIBRARY)
   ART_TEST_HOST_DEX_FILES += $$(LOCAL_MODULE_PATH)/$$(LOCAL_MODULE).jar
 endef
-$(foreach dir,$(TEST_DEX_DIRECTORIES), $(eval $(call build-art-test-dex,art-test-dex,$(dir),$(ART_NATIVETEST_OUT))))
-$(foreach dir,$(TEST_OAT_DIRECTORIES), $(eval $(call build-art-test-dex,oat-test-dex,$(dir),$(ART_TEST_OUT))))
+#$(foreach dir,$(TEST_DEX_DIRECTORIES), $(eval $(call build-art-test-dex,art-test-dex,$(dir),$(ART_NATIVETEST_OUT))))
+#$(foreach dir,$(TEST_OAT_DIRECTORIES), $(eval $(call build-art-test-dex,oat-test-dex,$(dir),$(ART_TEST_OUT))))
+$(foreach dir,HelloWorld, $(eval $(call build-art-test-dex,oat-test-dex,$(dir),$(ART_TEST_OUT))))
 
 ########################################################################
 
diff --git a/src/compiled_method.cc b/src/compiled_method.cc
index 980fdc9..89b5496 100644
--- a/src/compiled_method.cc
+++ b/src/compiled_method.cc
@@ -63,7 +63,7 @@
 void CompiledMethod::SetGcMap(const std::vector<uint8_t>& gc_map) {
   CHECK_NE(gc_map.size(), 0U);
 
-#if !defined(ART_USE_LLVM_COMPILER)
+#if !defined(ART_USE_LLVM_COMPILER) && !defined(ART_USE_GREENLAND_COMPILER)
   // Should only be used with CompiledMethods created with the non-LLVM compilers.
   CHECK_NE(mapping_table_.size(), 0U);
 #endif
diff --git a/src/compiler.cc b/src/compiler.cc
index d833d63..6e3cd46 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -258,10 +258,12 @@
   const char* suffix = (kIsDebugBuild ? "d" : "");
 
   // Work out the filename for the compiler library.
-#if !defined(ART_USE_LLVM_COMPILER)
-  std::string library_name(StringPrintf("art%s-compiler-%s", suffix, instruction_set_name.c_str()));
-#else
+#if defined(ART_USE_LLVM_COMPILER)
   std::string library_name(StringPrintf("art%s-compiler-llvm", suffix));
+#elif defined(ART_USE_GREENLAND_COMPILER)
+  std::string library_name(StringPrintf("art%s-compiler-greenland", suffix));
+#else
+  std::string library_name(StringPrintf("art%s-compiler-%s", suffix, instruction_set_name.c_str()));
 #endif
   std::string filename(StringPrintf(OS_SHARED_LIB_FORMAT_STR, library_name.c_str()));
 
@@ -330,7 +332,7 @@
   }
   VLOG(compiler) << "dlopen(\"" << compiler_so_name << "\", RTLD_LAZY) returned " << compiler_library_;
 
-#if defined(ART_USE_LLVM_COMPILER)
+#if defined(ART_USE_LLVM_COMPILER) || defined(ART_USE_GREENLAND_COMPILER)
   // Initialize compiler_context_
   typedef void (*InitCompilerContextFn)(Compiler&);
 
diff --git a/src/greenland/arm/arm_codegen_machine.cc b/src/greenland/arm/arm_codegen_machine.cc
new file mode 100644
index 0000000..c85aeed
--- /dev/null
+++ b/src/greenland/arm/arm_codegen_machine.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "arm_codegen_machine.h"
+
+#include "greenland/target_registry.h"
+
+namespace art {
+namespace greenland {
+
+ARMCodeGenMachine::ARMCodeGenMachine() : TargetCodeGenMachine() {
+}
+
+ARMCodeGenMachine::~ARMCodeGenMachine() {
+}
+
+void InitializeARMCodeGenMachine() {
+  RegisterTargetCodeGenMachine<ARMCodeGenMachine> X(kArm);
+  RegisterTargetCodeGenMachine<ARMCodeGenMachine> Y(kThumb2);
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/arm/arm_codegen_machine.h b/src/greenland/arm/arm_codegen_machine.h
new file mode 100644
index 0000000..c78ddf8
--- /dev/null
+++ b/src/greenland/arm/arm_codegen_machine.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_ARM_CODEGEN_MACHINE_H_
+#define ART_SRC_GREENLAND_ARM_CODEGEN_MACHINE_H_
+
+#include "greenland/target_codegen_machine.h"
+
+namespace art {
+namespace greenland {
+
+class ARMCodeGenMachine : public TargetCodeGenMachine {
+ private:
+
+ public:
+  ARMCodeGenMachine();
+  virtual ~ARMCodeGenMachine();
+
+  virtual TargetLIREmitter* CreateLIREmitter(const llvm::Function& func,
+                                             const OatCompilationUnit& cunit,
+                                             DexLang::Context& dex_lang_ctx) {
+    return NULL;
+  }
+
+  virtual RegisterAllocator* GetRegisterAllocator() {
+    return NULL;
+  }
+
+  virtual TargetAssembler* GetAssembler() {
+    return NULL;
+  }
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_ARM_CODEGEN_MACHINE_H_
diff --git a/src/greenland/arm/arm_invoke_stub_compiler.cc b/src/greenland/arm/arm_invoke_stub_compiler.cc
new file mode 100644
index 0000000..f14b35f
--- /dev/null
+++ b/src/greenland/arm/arm_invoke_stub_compiler.cc
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "asm_support.h"
+#include "compiled_method.h"
+#include "compiler.h"
+#include "greenland/target_registry.h"
+#include "oat/utils/arm/assembler_arm.h"
+#include "oat/utils/assembler.h"
+#include "object.h"
+
+#include <stdint.h>
+
+#include <algorithm>
+
+using namespace art;
+using namespace art::arm;
+
+namespace {
+
+// Creates a function which invokes a managed method with an array of
+// arguments.
+//
+// At the time of call, the environment looks something like this:
+//
+// R0 = method pointer
+// R1 = receiver pointer or NULL for static methods
+// R2 = (managed) thread pointer
+// R3 = argument array or NULL for no argument methods
+// [SP] = JValue* result or NULL for void returns
+//
+// As the JNI call has already transitioned the thread into the
+// "running" state the remaining responsibilities of this routine are
+// to save the native register value and restore the managed thread
+// register and transfer arguments from the array into register and on
+// the stack, if needed.  On return, the thread register must be
+// shuffled and the return value must be store into the result JValue.
+CompiledInvokeStub* CreateInvokeStub(bool is_static, const char* shorty, uint32_t shorty_len) {
+  UniquePtr<ArmAssembler> assembler(down_cast<ArmAssembler*>(Assembler::Create(kArm)));
+#define __ assembler->
+  size_t num_arg_array_bytes = NumArgArrayBytes(shorty, shorty_len);
+  // Size of frame = spill of R4,R9/LR + Method* + possible receiver + arg array size
+  // Note, space is left in the frame to flush arguments in registers back to out locations.
+  size_t unpadded_frame_size = (4 * kPointerSize) +
+                               (is_static ? 0 : kPointerSize) +
+                               num_arg_array_bytes;
+  size_t frame_size = RoundUp(unpadded_frame_size, kStackAlignment);
+
+  // Spill R4,R9 and LR
+  RegList save = (1 << R9) | (1 << R4);
+  __ PushList(save | (1 << LR));
+
+  // Move the managed thread pointer into R9.
+  __ mov(R9, ShifterOperand(R2));
+
+  // Reset R4 to suspend check interval
+  __ LoadImmediate(R4, SUSPEND_CHECK_INTERVAL);
+
+  // Move frame down for arguments less 3 pushed values above
+  __ AddConstant(SP, -frame_size + (3 * kPointerSize));
+
+  // Can either get 3 or 2 arguments into registers
+  size_t reg_bytes = (is_static ? 3 : 2) * kPointerSize;
+  // Bytes passed by stack
+  size_t stack_bytes;
+  if (num_arg_array_bytes > reg_bytes) {
+    stack_bytes = num_arg_array_bytes - reg_bytes;
+  } else {
+    stack_bytes = 0;
+    reg_bytes = num_arg_array_bytes;
+  }
+
+  // Method* at bottom of frame is null thereby terminating managed stack crawls
+  __ LoadImmediate(IP, 0, AL);
+  __ StoreToOffset(kStoreWord, IP, SP, 0);
+
+  // Copy values onto the stack.
+  size_t src_offset = 0;
+  size_t dst_offset = (is_static ? 1 : 2) * kPointerSize;
+  for (size_t i = 1; i < shorty_len; ++i) {
+    switch (shorty[i]) {
+      case 'D':
+      case 'J':
+        // Move both pointers 64 bits.
+        __ LoadFromOffset(kLoadWord, IP, R3, src_offset);
+        src_offset += kPointerSize;
+        __ StoreToOffset(kStoreWord, IP, SP, dst_offset);
+        dst_offset += kPointerSize;
+
+        __ LoadFromOffset(kLoadWord, IP, R3, src_offset);
+        src_offset += kPointerSize;
+        __ StoreToOffset(kStoreWord, IP, SP, dst_offset);
+        dst_offset += kPointerSize;
+        break;
+      default:
+        // Move the source pointer sizeof(JValue) and the destination pointer 32 bits.
+        __ LoadFromOffset(kLoadWord, IP, R3, src_offset);
+        src_offset += sizeof(JValue);
+        __ StoreToOffset(kStoreWord, IP, SP, dst_offset);
+        dst_offset += kPointerSize;
+        break;
+    }
+  }
+
+  // Move all the register arguments into place.
+  dst_offset = (is_static ? 1 : 2) * kPointerSize;
+  if (is_static) {
+    if (reg_bytes > 0 && num_arg_array_bytes > 0) {
+      __ LoadFromOffset(kLoadWord, R1, SP, dst_offset + 0);
+      if (reg_bytes > 4 && num_arg_array_bytes > 4) {
+        __ LoadFromOffset(kLoadWord, R2, SP, dst_offset + 4);
+        if (reg_bytes > 8 && num_arg_array_bytes > 8) {
+          __ LoadFromOffset(kLoadWord, R3, SP, dst_offset + 8);
+        }
+      }
+    }
+  } else {
+    if (reg_bytes > 0 && num_arg_array_bytes > 0) {
+      __ LoadFromOffset(kLoadWord, R2, SP, dst_offset + 0);
+      if (reg_bytes > 4 && num_arg_array_bytes > 4) {
+        __ LoadFromOffset(kLoadWord, R3, SP, dst_offset + 4);
+      }
+    }
+  }
+
+  // Load the code pointer we are about to call.
+  __ LoadFromOffset(kLoadWord, IP, R0, Method::GetCodeOffset().Int32Value());
+
+  // Do the call.
+  __ blx(IP);
+
+  // If the method returns a value, store it to the result pointer.
+  if (shorty[0] != 'V') {
+    // Load the result JValue pointer of the stub caller's out args.
+    __ LoadFromOffset(kLoadWord, IP, SP, frame_size);
+    StoreOperandType type = (shorty[0] == 'J' || shorty[0] == 'D') ? kStoreWordPair : kStoreWord;
+    __ StoreToOffset(type, R0, IP, 0);
+  }
+
+  // Remove the frame less the spilled R4, R9 and LR
+  __ AddConstant(SP, frame_size - (3 * kPointerSize));
+
+  // Pop R4, R9 and the LR into PC
+  __ PopList(save | (1 << PC));
+  // TODO: store native_entry in the stub table
+  std::vector<uint8_t> code(assembler->CodeSize());
+  MemoryRegion region(&code[0], code.size());
+  assembler->FinalizeInstructions(region);
+  return new CompiledInvokeStub(code);
+#undef __
+}
+
+CompiledInvokeStub* ARMInvokeStubCompiler(art::Compiler& /*compiler*/,
+                                          bool is_static,
+                                          const char* shorty,
+                                          uint32_t shorty_len) {
+  return CreateInvokeStub(is_static, shorty, shorty_len);
+}
+
+} // anonymous namespace
+
+namespace art {
+namespace greenland {
+
+void InitializeARMInvokeStubCompiler() {
+  TargetRegistry::RegisterInvokeStubCompiler(kArm, ARMInvokeStubCompiler);
+  TargetRegistry::RegisterInvokeStubCompiler(kThumb2, ARMInvokeStubCompiler);
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/backend_types.h b/src/greenland/backend_types.h
new file mode 100644
index 0000000..483d766
--- /dev/null
+++ b/src/greenland/backend_types.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_BACKEND_TYPES_H_
+#define ART_SRC_GREENLAND_BACKEND_TYPES_H_
+
+#include "logging.h"
+
+namespace art {
+namespace greenland {
+
+enum JType {
+  kVoid,
+  kBoolean,
+  kByte,
+  kChar,
+  kShort,
+  kInt,
+  kLong,
+  kFloat,
+  kDouble,
+  kObject,
+};
+
+
+enum JTypeSpace {
+  kAccurate,
+  kReg,
+  kField,
+  kArray,
+};
+
+
+enum RegCategory {
+  kRegUnknown,
+  kRegZero,
+  kRegCat1nr,
+  kRegCat2,
+  kRegObject,
+};
+
+
+inline JType GetJTypeFromShorty(char shorty_jty) {
+  switch (shorty_jty) {
+  case 'V':
+    return kVoid;
+
+  case 'Z':
+    return kBoolean;
+
+  case 'B':
+    return kByte;
+
+  case 'C':
+    return kChar;
+
+  case 'S':
+    return kShort;
+
+  case 'I':
+    return kInt;
+
+  case 'J':
+    return kLong;
+
+  case 'F':
+    return kFloat;
+
+  case 'D':
+    return kDouble;
+
+  case 'L':
+    return kObject;
+
+  default:
+    LOG(FATAL) << "Unknown Dalvik shorty descriptor: " << shorty_jty;
+    return kVoid;
+  }
+}
+
+
+inline RegCategory GetRegCategoryFromJType(JType jty) {
+  switch (jty) {
+  case kVoid:
+    return kRegUnknown;
+
+  case kBoolean:
+  case kByte:
+  case kChar:
+  case kShort:
+  case kInt:
+  case kFloat:
+    return kRegCat1nr;
+
+  case kLong:
+  case kDouble:
+    return kRegCat2;
+
+  case kObject:
+    return kRegObject;
+  }
+
+  LOG(FATAL) << "Unknown java type: " << jty;
+  return kRegUnknown;
+}
+
+
+inline RegCategory GetRegCategoryFromShorty(char shorty) {
+  return GetRegCategoryFromJType(GetJTypeFromShorty(shorty));
+}
+
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_BACKEND_TYPES_H_
diff --git a/src/greenland/dalvik_reg.cc b/src/greenland/dalvik_reg.cc
new file mode 100644
index 0000000..eb4a89c
--- /dev/null
+++ b/src/greenland/dalvik_reg.cc
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dalvik_reg.h"
+
+#include "dex_lang.h"
+#include "ir_builder.h"
+#include "intrinsic_helper.h"
+
+#include <llvm/Function.h>
+
+using namespace art;
+using namespace art::greenland;
+
+namespace {
+
+  class DalvikArgReg : public DalvikReg {
+   public:
+    DalvikArgReg(DexLang& dex_lang, unsigned reg_idx, JType jty);
+
+    virtual llvm::Value* GetValue(JType jty, JTypeSpace space);
+    virtual void SetValue(JType jty, JTypeSpace space, llvm::Value* value);
+
+   private:
+    llvm::Value* reg_addr_;
+    JType jty_;
+
+    inline void CheckJType(JType jty) const {
+      CHECK_EQ(jty, jty_) << "Get value of type " << jty << " from Dalvik "
+                             "argument register v" << reg_idx_ << "(type: "
+                          << jty_ << ") without type coercion!";
+      return;
+    }
+  };
+
+  class DalvikLocalVarReg : public DalvikReg {
+   public:
+    DalvikLocalVarReg(DexLang& dex_lang, unsigned reg_idx);
+
+    virtual llvm::Value* GetValue(JType jty, JTypeSpace space);
+    virtual void SetValue(JType jty, JTypeSpace space, llvm::Value* value);
+
+   private:
+    llvm::Value* GetRawAddr(RegCategory cat);
+
+   private:
+    llvm::Value* reg_32_;
+    llvm::Value* reg_64_;
+    llvm::Value* reg_obj_;
+  };
+} // anonymous namespace
+
+
+//----------------------------------------------------------------------------
+// Dalvik Register
+//----------------------------------------------------------------------------
+
+DalvikReg* DalvikReg::CreateArgReg(DexLang& dex_lang, unsigned reg_idx,
+                                   JType jty) {
+  return new DalvikArgReg(dex_lang, reg_idx, jty);
+}
+
+DalvikReg* DalvikReg::CreateLocalVarReg(DexLang& dex_lang, unsigned reg_idx) {
+  return new DalvikLocalVarReg(dex_lang, reg_idx);
+}
+
+DalvikReg::DalvikReg(DexLang& dex_lang, unsigned reg_idx)
+    : dex_lang_(dex_lang), irb_(dex_lang.GetIRBuilder()), reg_idx_(reg_idx),
+      shadow_frame_entry_idx_(-1) {
+}
+
+void DalvikReg::SetShadowEntry(llvm::Value* root_object) {
+  if (shadow_frame_entry_idx_ < 0) {
+    shadow_frame_entry_idx_ = dex_lang_.AllocShadowFrameEntry(reg_idx_);
+  }
+
+  irb_.CreateCall2(irb_.GetIntrinsics(IntrinsicHelper::SetShadowFrameEntry),
+                  root_object, irb_.getInt32(shadow_frame_entry_idx_));
+
+  return;
+}
+
+//----------------------------------------------------------------------------
+// Dalvik Argument Register
+//----------------------------------------------------------------------------
+DalvikArgReg::DalvikArgReg(DexLang& dex_lang, unsigned reg_idx, JType jty)
+    : DalvikReg(dex_lang, reg_idx), jty_(jty) {
+  reg_addr_ = dex_lang_.AllocateDalvikReg(jty, reg_idx);
+  DCHECK(reg_addr_ != NULL);
+}
+
+llvm::Value* DalvikArgReg::GetValue(JType jty, JTypeSpace space) {
+  DCHECK_NE(jty, kVoid) << "Dalvik register will never be void type";
+
+  switch (space) {
+    case kReg:
+    case kField: {
+      // Currently, kField is almost the same with kReg.
+      RegCategory cat = GetRegCategoryFromJType(jty_);
+      CHECK_EQ(cat, GetRegCategoryFromJType(jty)) << "Get value of type " << jty
+                                                  << "has different register "
+                                                     "category from the value "
+                                                     "contained in the register"
+                                                  << reg_idx_ << "(type: "
+                                                  << jty_ << ")";
+      switch (jty_) {
+        case kVoid: {
+          break;
+        }
+        case kBoolean:
+        case kChar: {
+          return irb_.CreateZExt(irb_.CreateLoad(reg_addr_), irb_.GetJIntTy());
+        }
+        case kByte:
+        case kShort: {
+          return irb_.CreateSExt(irb_.CreateLoad(reg_addr_), irb_.GetJIntTy());
+        }
+        case kFloat: {
+          return irb_.CreateBitCast(irb_.CreateLoad(reg_addr_),
+                                    irb_.GetJIntTy());
+        }
+        case kDouble: {
+          return irb_.CreateBitCast(irb_.CreateLoad(reg_addr_),
+                                    irb_.GetJLongTy());
+        }
+        case kInt:
+        case kLong:
+        case kObject: {
+          return irb_.CreateLoad(reg_addr_);
+        }
+        default: {
+          LOG(FATAL) << "Unexpected register type: " << jty;
+          break;
+        }
+      }
+      break;
+    }
+    case kArray: {
+      switch (jty) {
+        case kVoid: {
+          LOG(FATAL) << "Dalvik register with void type has no value";
+          return NULL;
+        }
+        case kBoolean: {
+          CheckJType(jty);
+          // NOTE: In array type space, boolean is i8, while in accurate type
+          // space, boolean is i1. For the other cases, array type space is
+          // equal to accurate type space.
+          return irb_.CreateZExt(irb_.CreateLoad(reg_addr_), irb_.GetJByteTy());
+        }
+        case kByte:
+        case kChar:
+        case kShort:
+        case kInt:
+        case kLong:
+        case kFloat:
+        case kDouble:
+        case kObject: {
+          CheckJType(jty);
+          return irb_.CreateLoad(reg_addr_);
+        }
+        default: {
+          LOG(FATAL) << "Unexpected register type: " << jty;
+          break;
+        }
+      }
+    }
+    case kAccurate: {
+      CheckJType(jty);
+      return irb_.CreateLoad(reg_addr_);
+    }
+  }
+  return NULL;
+}
+
+void DalvikArgReg::SetValue(JType jty, JTypeSpace space, llvm::Value* value) {
+  if ((jty == jty_) && (space == kAccurate)) {
+    irb_.CreateStore(value, reg_addr_);
+    if (jty == kObject) {
+      SetShadowEntry(value);
+    }
+  } else {
+    LOG(FATAL) << "Normal .dex file doesn't use argument register for method-"
+                  "local variable!";
+  }
+  return;
+}
+
+//----------------------------------------------------------------------------
+// Dalvik Local Variable Register
+//----------------------------------------------------------------------------
+
+DalvikLocalVarReg::DalvikLocalVarReg(DexLang& dex_lang, unsigned reg_idx)
+    : DalvikReg(dex_lang, reg_idx), reg_32_(NULL), reg_64_(NULL),
+      reg_obj_(NULL) {
+}
+
+llvm::Value* DalvikLocalVarReg::GetRawAddr(RegCategory cat) {
+  switch (cat) {
+    case kRegCat1nr: {
+      if (reg_32_ == NULL) {
+        reg_32_ = dex_lang_.AllocateDalvikReg(kInt, reg_idx_);
+      }
+      return reg_32_;
+    }
+    case kRegCat2: {
+      if (reg_64_ == NULL) {
+        reg_64_ = dex_lang_.AllocateDalvikReg(kLong, reg_idx_);
+      }
+      return reg_64_;
+    }
+    case kRegObject: {
+      if (reg_obj_ == NULL) {
+        reg_obj_ = dex_lang_.AllocateDalvikReg(kObject, reg_idx_);
+      }
+      return reg_obj_;
+    }
+    default: {
+      LOG(FATAL) << "Unexpected register category: " << cat;
+      return NULL;
+    }
+  }
+  return NULL;
+}
+
+llvm::Value* DalvikLocalVarReg::GetValue(JType jty, JTypeSpace space) {
+  DCHECK_NE(jty, kVoid) << "Dalvik register will never be void type";
+
+  switch (space) {
+    case kReg:
+    case kField: {
+      // float and double require bitcast to get their value from the integer
+      // register.
+      DCHECK((jty != kFloat) && (jty != kDouble));
+      return irb_.CreateLoad(GetRawAddr(GetRegCategoryFromJType(jty)));
+    }
+    case kAccurate:
+    case kArray: {
+      switch (jty) {
+        case kVoid: {
+          LOG(FATAL) << "Dalvik register with void type has no value";
+          return NULL;
+        }
+        case kBoolean:
+        case kChar:
+        case kByte:
+        case kShort: {
+          // NOTE: In array type space, boolean is truncated from i32 to i8,
+          // while in accurate type space, boolean is truncated from i32 to i1.
+          // For the other cases, array type space is equal to accurate type
+          // space.
+          return irb_.CreateTrunc(irb_.CreateLoad(GetRawAddr(kRegCat1nr)),
+                                  irb_.GetJType(jty, space));
+        }
+        case kFloat: {
+          return irb_.CreateBitCast(irb_.CreateLoad(GetRawAddr(kRegCat1nr)),
+                                    irb_.GetJType(jty, space));
+        }
+        case kDouble: {
+          return irb_.CreateBitCast(irb_.CreateLoad(GetRawAddr(kRegCat2)),
+                                    irb_.GetJType(jty, space));
+        }
+        case kInt:
+        case kLong:
+        case kObject: {
+          return irb_.CreateLoad(GetRawAddr(GetRegCategoryFromJType(jty)));
+        }
+        default: {
+          LOG(FATAL) << "Unexpected register type: " << jty;
+          break;
+        }
+      }
+    }
+    default: {
+      LOG(FATAL) << "Unexpected register space: " << space;
+      break;
+    }
+  }
+  return NULL;
+}
+
+void DalvikLocalVarReg::SetValue(JType jty, JTypeSpace space,
+                                 llvm::Value* value) {
+  DCHECK_NE(jty, kVoid) << "Dalvik register should never hold void type";
+
+  if (jty == kObject) {
+    SetShadowEntry(value);
+  }
+
+  switch (space) {
+    case kReg:
+    case kField: {
+      // float and double require bitcast to get their value from the integer
+      // register.
+      DCHECK((jty != kFloat) && (jty != kDouble));
+      irb_.CreateStore(value, GetRawAddr(GetRegCategoryFromJType(jty)));
+      return;
+    }
+    case kAccurate:
+    case kArray: {
+      switch (jty) {
+        case kVoid: {
+          break;
+        }
+        case kBoolean:
+        case kChar: {
+          // NOTE: In accurate type space, we have to zero extend boolean from
+          // i1 to i32, and char from i16 to i32.  In array type space, we have
+          // to zero extend boolean from i8 to i32, and char from i16 to i32.
+          value = irb_.CreateZExt(value, irb_.GetJIntTy());
+          irb_.CreateStore(value, GetRawAddr(kRegCat1nr));
+          break;
+        }
+        case kByte:
+        case kShort: {
+          // NOTE: In accurate type space, we have to signed extend byte from
+          // i8 to i32, and short from i16 to i32.  In array type space, we have
+          // to sign extend byte from i8 to i32, and short from i16 to i32.
+          value = irb_.CreateSExt(value, irb_.GetJIntTy());
+          irb_.CreateStore(value, GetRawAddr(kRegCat1nr));
+          break;
+        }
+        case kFloat: {
+          value = irb_.CreateBitCast(value, irb_.GetJIntTy());
+          irb_.CreateStore(value, GetRawAddr(kRegCat1nr));
+          break;
+        }
+        case kDouble: {
+          value = irb_.CreateBitCast(value, irb_.GetJLongTy());
+          irb_.CreateStore(value, GetRawAddr(kRegCat2));
+          break;
+        }
+        case kInt:
+        case kLong:
+        case kObject: {
+          irb_.CreateStore(value, GetRawAddr(GetRegCategoryFromJType(jty)));
+          break;
+        }
+        default: {
+          LOG(FATAL) << "Unexpected register type: " << jty;
+          return;
+        }
+      }
+      return;
+    }
+    default: {
+      LOG(FATAL) << "Unexpected register space: " << space;
+      return;
+    }
+  }
+}
+
diff --git a/src/greenland/dalvik_reg.h b/src/greenland/dalvik_reg.h
new file mode 100644
index 0000000..78247cc
--- /dev/null
+++ b/src/greenland/dalvik_reg.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_DALVIK_REG_H_
+#define ART_SRC_GREENLAND_DALVIK_REG_H_
+
+#include "backend_types.h"
+
+namespace llvm {
+  class Type;
+  class Value;
+}
+
+namespace art {
+namespace greenland {
+
+class DexLang;
+class IRBuilder;
+
+class DalvikReg {
+ public:
+  static DalvikReg* CreateArgReg(DexLang& dex_lang, unsigned reg_idx,
+                                 JType jty);
+
+  static DalvikReg* CreateLocalVarReg(DexLang& dex_lang, unsigned reg_idx);
+
+  virtual ~DalvikReg() { }
+
+  virtual llvm::Value* GetValue(JType jty, JTypeSpace space) = 0;
+  llvm::Value* GetValue(char shorty, JTypeSpace space) {
+    return GetValue(GetJTypeFromShorty(shorty), space);
+  }
+
+  virtual void SetValue(JType jty, JTypeSpace space, llvm::Value* value) = 0;
+  void SetValue(char shorty, JTypeSpace space, llvm::Value* value) {
+    return SetValue(GetJTypeFromShorty(shorty), space, value);
+  }
+
+ protected:
+  DalvikReg(DexLang& dex_lang, unsigned reg_idx);
+
+  void SetShadowEntry(llvm::Value* root_object);
+
+ protected:
+  DexLang& dex_lang_;
+  IRBuilder& irb_;
+  unsigned reg_idx_;
+  int shadow_frame_entry_idx_;
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_DALVIK_REG_H_
diff --git a/src/greenland/dex_lang.cc b/src/greenland/dex_lang.cc
new file mode 100644
index 0000000..18ce4b4
--- /dev/null
+++ b/src/greenland/dex_lang.cc
@@ -0,0 +1,2830 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dex_lang.h"
+
+#include "intrinsic_helper.h"
+
+#include "atomic.h"
+#include "inferred_reg_category_map.h"
+#include "object.h" // FIXME: include this in oat_compilation_unit.h
+#include "oat_compilation_unit.h"
+#include "stl_util.h"
+#include "stringprintf.h"
+#include "verifier/method_verifier.h"
+
+#include <llvm/Analysis/Passes.h>
+#include <llvm/Analysis/Verifier.h>
+#include <llvm/BasicBlock.h>
+#include <llvm/Function.h>
+#include <llvm/Module.h>
+#include <llvm/PassManager.h>
+#include <llvm/Support/InstIterator.h>
+#include <llvm/Transforms/Scalar.h>
+
+namespace art {
+namespace greenland {
+
+//----------------------------------------------------------------------------
+// DexLang::Context
+//----------------------------------------------------------------------------
+DexLang::Context::Context()
+    : context_(), module_(NULL), ref_count_(1), mem_usage_(0) {
+  module_ = new llvm::Module("art", context_);
+
+  // Initialize the contents of an empty module
+  // Type of "JavaObject"
+  llvm::StructType::create(context_, "JavaObject");
+  // Type of "Method"
+  llvm::StructType::create(context_, "Method");
+  // Type of "Thread"
+  llvm::StructType::create(context_, "Thread");
+
+  // Initalize the DexLang intrinsics
+  intrinsic_helper_ = new IntrinsicHelper(context_, *module_);
+
+  return;
+}
+
+DexLang::Context::~Context() {
+  delete intrinsic_helper_;
+  return;
+}
+
+DexLang::Context& DexLang::Context::IncRef() {
+  android_atomic_inc(&ref_count_);
+  return *this;
+}
+
+void DexLang::Context::DecRef() {
+  int32_t old_ref_count = android_atomic_dec(&ref_count_);
+  if (old_ref_count <= 1) {
+    delete this;
+  }
+  return;
+}
+
+void DexLang::Context::AddMemUsageApproximation(size_t usage) {
+  android_atomic_add(static_cast<int32_t>(usage), &mem_usage_);
+  return;
+}
+
+//----------------------------------------------------------------------------
+// Constructor, Destructor and APIs
+//----------------------------------------------------------------------------
+DexLang::DexLang(DexLang::Context& context, Compiler& compiler,
+                 OatCompilationUnit& cunit)
+    : dex_lang_ctx_(context.IncRef()), compiler_(compiler), cunit_(cunit),
+      dex_file_(cunit.GetDexFile()), code_item_(cunit.GetCodeItem()),
+      dex_cache_(cunit.GetDexCache()),
+      context_(context.GetLLVMContext()), module_(context.GetOutputModule()),
+      intrinsic_helper_(context.GetIntrinsicHelper()),
+      irb_(context.GetLLVMContext(), context.GetOutputModule(),
+           context.GetIntrinsicHelper()),
+      func_(NULL), reg_alloc_bb_(NULL), arg_reg_init_bb_(NULL),
+      basic_blocks_(cunit.GetCodeItem()->insns_size_in_code_units_),
+      retval_(NULL), retval_jty_(kVoid),
+      landing_pads_bb_(cunit.GetCodeItem()->tries_size_, NULL),
+      exception_unwind_bb_(NULL), cur_try_item_offset(-1),
+      require_shadow_frame(false), num_shadow_frame_entries_(0) {
+  if (cunit.GetCodeItem()->tries_size_ > 0) {
+    cur_try_item_offset = 0;
+  }
+  return;
+}
+
+DexLang::~DexLang() {
+  dex_lang_ctx_.DecRef();
+  return;
+}
+
+llvm::Function* DexLang::Build() {
+  if (!CreateFunction() ||
+      !EmitPrologue() ||
+      !EmitInstructions() ||
+      !EmitPrologueAllcaShadowFrame() ||
+      !EmitPrologueLinkBasicBlocks() ||
+      !PrettyLayoutExceptionBasicBlocks() ||
+      !VerifyFunction() ||
+      !OptimizeFunction() ||
+      !RemoveRedundantPendingExceptionChecks()) {
+    return NULL;
+  }
+
+  // NOTE: From statistic, the bitcode size is 4.5 times bigger than the
+  // Dex file.  Besides, we have to convert the code unit into bytes.
+  // Thus, we got our magic number 9.
+  dex_lang_ctx_.AddMemUsageApproximation(
+      code_item_->insns_size_in_code_units_ * 900);
+
+  return func_;
+}
+
+llvm::Value* DexLang::AllocateDalvikReg(JType jty, unsigned reg_idx) {
+  RegCategory cat = GetRegCategoryFromJType(jty);
+  llvm::Type* type = irb_.GetJType(jty, kAccurate);
+
+  DCHECK_NE(type, static_cast<llvm::Type*>(NULL));
+
+  std::string reg_name;
+  switch (cat) {
+    case kRegCat1nr: {
+      reg_name = StringPrintf("r%u", reg_idx);
+      break;
+    }
+    case kRegCat2: {
+      reg_name = StringPrintf("w%u", reg_idx);
+      break;
+    }
+    case kRegObject: {
+      reg_name = StringPrintf("p%u", reg_idx);
+      break;
+    }
+    default: {
+      LOG(FATAL) << "Unknown register category for allocation: " << cat;
+    }
+  }
+
+  // Save current IR builder insert point
+  DCHECK(reg_alloc_bb_ != NULL);
+  llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP();
+  irb_.SetInsertPoint(reg_alloc_bb_);
+
+  // Alloca
+  llvm::Value* reg_addr = irb_.CreateAlloca(type, 0, reg_name);
+
+  // Restore IRBuilder insert point
+  irb_.restoreIP(irb_ip_original);
+
+  DCHECK_NE(reg_addr, static_cast<llvm::Value*>(NULL));
+
+  return reg_addr;
+}
+
+//----------------------------------------------------------------------------
+// Basic Block Helper Functions
+//----------------------------------------------------------------------------
+llvm::BasicBlock* DexLang::GetBasicBlock(unsigned dex_pc) {
+  DCHECK(dex_pc < code_item_->insns_size_in_code_units_);
+
+  llvm::BasicBlock* basic_block = basic_blocks_[dex_pc];
+
+  if (!basic_block) {
+    basic_block = CreateBasicBlockWithDexPC(dex_pc);
+    basic_blocks_[dex_pc] = basic_block;
+  }
+
+  return basic_block;
+}
+
+llvm::BasicBlock* DexLang::CreateBasicBlockWithDexPC(unsigned dex_pc,
+                                                     const char* postfix) {
+  std::string name;
+
+  if (postfix) {
+    StringAppendF(&name, "B%04x.%s", dex_pc, postfix);
+  } else {
+    StringAppendF(&name, "B%04x", dex_pc);
+  }
+
+  return llvm::BasicBlock::Create(context_, name, func_);
+}
+
+llvm::BasicBlock* DexLang::GetNextBasicBlock(unsigned dex_pc) {
+  const Instruction* insn = Instruction::At(code_item_->insns_ + dex_pc);
+  return GetBasicBlock(dex_pc + insn->SizeInCodeUnits());
+}
+
+//----------------------------------------------------------------------------
+// Exception Handling
+//----------------------------------------------------------------------------
+int32_t DexLang::GetTryItemOffset(unsigned dex_pc) {
+  if (cur_try_item_offset >= 0) {
+    // Search over the try item.
+    do {
+      const DexFile::TryItem* ti =
+          DexFile::GetTryItems(*code_item_, cur_try_item_offset);
+      if (dex_pc < ti->start_addr_) {
+        return -1;
+      }
+
+      if (dex_pc < (ti->start_addr_ + ti->insn_count_)) {
+        return cur_try_item_offset;
+      }
+
+      cur_try_item_offset++;
+    } while (cur_try_item_offset < code_item_->tries_size_);
+
+    // Search to the end of try items and Cannot find any try item corresponding
+    // to the dex_pc.
+    cur_try_item_offset = -1;
+  }
+
+  return cur_try_item_offset;
+}
+
+llvm::BasicBlock* DexLang::GetLandingPadBasicBlock(unsigned dex_pc) {
+  // Find the try item for this address in this method
+  int32_t ti_offset = GetTryItemOffset(dex_pc);
+
+  if (ti_offset == -1) {
+    return NULL; // No landing pad is available for this address.
+  }
+
+  // Check for the existing landing pad basic block
+  DCHECK_GT(landing_pads_bb_.size(), static_cast<size_t>(ti_offset));
+  llvm::BasicBlock* block_lpad = landing_pads_bb_[ti_offset];
+
+  if (block_lpad != NULL) {
+    // We have generated landing pad for this try item already.  Return the
+    // same basic block.
+    return block_lpad;
+  }
+
+  // Get try item from code item
+  const DexFile::TryItem* ti = DexFile::GetTryItems(*code_item_, ti_offset);
+
+  std::string lpadname;
+
+#ifndef NDEBUG
+  StringAppendF(&lpadname, "lpad%d_%04x_to_%04x",
+                ti_offset, ti->start_addr_, ti->handler_off_);
+#endif
+
+  // Create landing pad basic block
+  block_lpad = llvm::BasicBlock::Create(context_, lpadname, func_);
+
+  // Change IRBuilder insert point
+  llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP();
+  irb_.SetInsertPoint(block_lpad);
+
+  // Find catch block with matching type
+  llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+  // Find catch block with matching type
+  llvm::Value* ti_offset_value = irb_.getInt32(ti_offset);
+
+  llvm::Value* catch_handler_index_value =
+      EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::FindCatchBlock,
+                           method_object_addr, ti_offset_value);
+
+  // Switch instruction (Go to unwind basic block by default)
+  llvm::SwitchInst* sw =
+      irb_.CreateSwitch(catch_handler_index_value, GetUnwindBasicBlock());
+
+  // Cases with matched catch block
+  CatchHandlerIterator iter(*code_item_, ti->start_addr_);
+
+  for (uint32_t c = 0; iter.HasNext(); iter.Next(), ++c) {
+    sw->addCase(irb_.getInt32(c), GetBasicBlock(iter.GetHandlerAddress()));
+  }
+
+  // Restore the orignal insert point for IRBuilder
+  irb_.restoreIP(irb_ip_original);
+
+  // Cache this landing pad
+  landing_pads_bb_[ti_offset] = block_lpad;
+
+  return block_lpad;
+}
+
+llvm::BasicBlock* DexLang::GetUnwindBasicBlock() {
+  // Check the existing unwinding baisc block block
+  if (exception_unwind_bb_ != NULL) {
+    return exception_unwind_bb_;
+  }
+
+  // Create new basic block for unwinding
+  exception_unwind_bb_ =
+      llvm::BasicBlock::Create(context_, "exception_unwind", func_);
+
+  // Change IRBuilder insert point
+  llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP();
+  irb_.SetInsertPoint(exception_unwind_bb_);
+
+  // Pop the shadow frame
+  EmitPopShadowFrame();
+
+  // Emit the code to return default value (zero) for the given return type.
+  char ret_shorty = cunit_.GetShorty()[0];
+  if (ret_shorty == 'V') {
+    irb_.CreateRetVoid();
+  } else {
+    irb_.CreateRet(irb_.GetJZero(ret_shorty));
+  }
+
+  // Restore the orignal insert point for IRBuilder
+  irb_.restoreIP(irb_ip_original);
+
+  return exception_unwind_bb_;
+}
+
+void DexLang::EmitBranchExceptionLandingPad(unsigned dex_pc) {
+  if (llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc)) {
+    irb_.CreateBr(lpad);
+  } else {
+    irb_.CreateBr(GetUnwindBasicBlock());
+  }
+}
+
+void DexLang::EmitGuard_DivZeroException(unsigned dex_pc,
+                                         llvm::Value* denominator,
+                                         JType op_jty) {
+  DCHECK(op_jty == kInt || op_jty == kLong) << op_jty;
+
+  llvm::Constant* zero = irb_.GetJZero(op_jty);
+
+  llvm::Value* equal_zero = irb_.CreateICmpEQ(denominator, zero);
+
+  llvm::BasicBlock* block_exception = CreateBasicBlockWithDexPC(dex_pc, "div0");
+
+  llvm::BasicBlock* block_continue = CreateBasicBlockWithDexPC(dex_pc, "cont");
+
+  irb_.CreateCondBr(equal_zero, block_exception, block_continue);
+
+  irb_.SetInsertPoint(block_exception);
+  EmitUpdateDexPC(dex_pc);
+  EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::ThrowDivZeroException);
+  EmitBranchExceptionLandingPad(dex_pc);
+
+  irb_.SetInsertPoint(block_continue);
+}
+
+void DexLang::EmitGuard_NullPointerException(unsigned dex_pc,
+                                             llvm::Value* object) {
+  llvm::Value* equal_null = irb_.CreateICmpEQ(object, irb_.GetJNull());
+
+  llvm::BasicBlock* block_exception =
+    CreateBasicBlockWithDexPC(dex_pc, "nullp");
+
+  llvm::BasicBlock* block_continue =
+    CreateBasicBlockWithDexPC(dex_pc, "cont");
+
+  irb_.CreateCondBr(equal_null, block_exception, block_continue);
+
+  irb_.SetInsertPoint(block_exception);
+
+  EmitUpdateDexPC(dex_pc);
+  EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::ThrowNullPointerException,
+                      irb_.getInt32(dex_pc));
+  EmitBranchExceptionLandingPad(dex_pc);
+
+  irb_.SetInsertPoint(block_continue);
+}
+
+void
+DexLang::EmitGuard_ArrayIndexOutOfBoundsException(unsigned dex_pc,
+                                                  llvm::Value* array,
+                                                  llvm::Value* index) {
+  llvm::Value* array_len = EmitLoadArrayLength(array);
+
+  llvm::Value* cmp = irb_.CreateICmpUGE(index, array_len);
+
+  llvm::BasicBlock* block_exception =
+    CreateBasicBlockWithDexPC(dex_pc, "overflow");
+
+  llvm::BasicBlock* block_continue =
+    CreateBasicBlockWithDexPC(dex_pc, "cont");
+
+  irb_.CreateCondBr(cmp, block_exception, block_continue);
+
+  irb_.SetInsertPoint(block_exception);
+
+  EmitUpdateDexPC(dex_pc);
+  EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::ThrowIndexOutOfBounds,
+                       index, array_len);
+  EmitBranchExceptionLandingPad(dex_pc);
+
+  irb_.SetInsertPoint(block_continue);
+  return;
+}
+
+void DexLang::EmitGuard_ArrayException(unsigned dex_pc,
+                                       llvm::Value* array, llvm::Value* index) {
+  EmitGuard_NullPointerException(dex_pc, array);
+  EmitGuard_ArrayIndexOutOfBoundsException(dex_pc, array, index);
+}
+
+void DexLang::EmitGuard_ExceptionLandingPad(unsigned dex_pc) {
+  llvm::Value* exception_pending =
+      EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::IsExceptionPending);
+
+  llvm::BasicBlock* block_cont = CreateBasicBlockWithDexPC(dex_pc, "cont");
+
+  if (llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc)) {
+    irb_.CreateCondBr(exception_pending, lpad, block_cont);
+  } else {
+    irb_.CreateCondBr(exception_pending, GetUnwindBasicBlock(), block_cont);
+  }
+
+  irb_.SetInsertPoint(block_cont);
+}
+
+//----------------------------------------------------------------------------
+// Garbage Collection Safe Point
+//----------------------------------------------------------------------------
+void DexLang::EmitGuard_GarbageCollectionSuspend() {
+  llvm::Value* thread_object_addr = EmitGetCurrentThread();
+  EmitInvokeIntrinsicNoThrow(IntrinsicHelper::TestSuspend, thread_object_addr);
+  return;
+}
+
+//----------------------------------------------------------------------------
+// Shadow Frame
+//----------------------------------------------------------------------------
+void DexLang::EmitUpdateDexPC(unsigned dex_pc) {
+  require_shadow_frame = true;
+  EmitInvokeIntrinsicNoThrow(IntrinsicHelper::UpdateDexPC,
+                             irb_.getInt32(dex_pc));
+  return;
+}
+
+void DexLang::EmitPopShadowFrame() {
+  EmitInvokeIntrinsicNoThrow(IntrinsicHelper::PopShadowFrame);
+  return;
+}
+
+unsigned DexLang::AllocShadowFrameEntry(unsigned reg_idx) {
+  return num_shadow_frame_entries_++;
+}
+
+//----------------------------------------------------------------------------
+// Code Generation
+//----------------------------------------------------------------------------
+bool DexLang::CreateFunction() {
+  std::string func_name(PrettyMethod(cunit_.GetDexMethodIndex(), *dex_file_,
+                                     /* with_signature */false));
+  llvm::FunctionType* func_type = GetFunctionType();
+
+  if (func_type == NULL) {
+    return false;
+  }
+
+  func_ = llvm::Function::Create(func_type, llvm::Function::ExternalLinkage,
+                                 func_name, &module_);
+
+  llvm::Function::arg_iterator arg_iter(func_->arg_begin());
+  llvm::Function::arg_iterator arg_end(func_->arg_end());
+
+  arg_iter->setName("method");
+  ++arg_iter;
+
+  if (!cunit_.IsStatic()) {
+    DCHECK_NE(arg_iter, arg_end);
+    arg_iter->setName("this");
+    ++arg_iter;
+  }
+
+  for (unsigned i = 0; arg_iter != arg_end; ++i, ++arg_iter) {
+    arg_iter->setName(StringPrintf("a%u", i));
+  }
+
+  return true;
+}
+
+llvm::FunctionType* DexLang::GetFunctionType() {
+  uint32_t shorty_size;
+  const char* shorty = cunit_.GetShorty(&shorty_size);
+  CHECK_GE(shorty_size, 1u);
+
+  // Get return type
+  llvm::Type* ret_type = irb_.GetJType(shorty[0], kAccurate);
+
+  // Get argument type
+  std::vector<llvm::Type*> args_type;
+
+  // method object
+  args_type.push_back(irb_.GetJMethodTy());
+
+  if (!cunit_.IsStatic()) {
+    // The first argument to non-static method is "this" object pointer
+    args_type.push_back(irb_.GetJObjectTy());
+  }
+
+  for (uint32_t i = 1; i < shorty_size; ++i) {
+    args_type.push_back(irb_.GetJType(shorty[i], kAccurate));
+  }
+
+  return llvm::FunctionType::get(ret_type, args_type, false);
+}
+
+bool DexLang::PrepareDalvikRegs() {
+  const unsigned num_regs = code_item_->registers_size_;
+  const unsigned num_ins = code_item_->ins_size_;
+  unsigned reg_idx = 0;
+
+  // Registers v[0..(num_regs - num_ins - 1)] are used for local variable
+  for (; reg_idx < (num_regs - num_ins); reg_idx++) {
+    regs_.push_back(DalvikReg::CreateLocalVarReg(*this, reg_idx));
+  }
+
+  // Registers v[(num_regs - num_ins)..(num_regs - 1)] are used for input
+  // argument
+  uint32_t shorty_size;
+  const char* shorty = cunit_.GetShorty(&shorty_size);
+
+  if (!cunit_.IsStatic()) {
+    // The first argument to non-static method is "this" object pointer
+    regs_.push_back(DalvikReg::CreateArgReg(*this, reg_idx++, kObject));
+  }
+
+  for (unsigned i = 1; i < shorty_size; i++) {
+    JType jty = GetJTypeFromShorty(shorty[i]);
+    regs_.push_back(DalvikReg::CreateArgReg(*this, reg_idx++, jty));
+    reg_idx++;
+
+    if (GetRegCategoryFromJType(jty) == kRegCat2) {
+      // Need a register pair to hold the value
+      regs_.push_back(NULL);
+      reg_idx++;
+    }
+  }
+
+  CHECK_EQ(num_regs, regs_.size());
+
+  return true;
+}
+
+bool DexLang::EmitPrologue() {
+  reg_alloc_bb_ = llvm::BasicBlock::Create(context_, "prologue.alloca", func_);
+
+  arg_reg_init_bb_ =
+      llvm::BasicBlock::Create(context_, "prologue.arginit", func_);
+
+  if (!PrepareDalvikRegs()) {
+    return false;
+  }
+
+  //Store argument to dalvik register
+  irb_.SetInsertPoint(arg_reg_init_bb_);
+  if (!EmitPrologueAssignArgRegister()) {
+    return false;
+  }
+
+  irb_.CreateBr(GetBasicBlock(0));
+
+  return true;
+}
+
+bool DexLang::EmitPrologueAssignArgRegister() {
+  llvm::Function::arg_iterator arg_iter(func_->arg_begin());
+
+  const unsigned num_regs = code_item_->registers_size_;
+  const unsigned num_ins = code_item_->ins_size_;
+  unsigned reg_idx = num_regs - num_ins;
+
+  uint32_t shorty_size;
+  const char* shorty = cunit_.GetShorty(&shorty_size);
+
+  // skip method object
+  ++arg_iter;
+
+  if (!cunit_.IsStatic()) {
+    // The first argument to non-static method is "this" object pointer
+    EmitStoreDalvikReg(reg_idx, kObject, kAccurate, arg_iter);
+    arg_iter++;
+    reg_idx++;
+  }
+
+  for (unsigned i = 1; i < shorty_size; i++, arg_iter++) {
+    JType jty = GetJTypeFromShorty(shorty[i]);
+    EmitStoreDalvikReg(reg_idx, jty, kAccurate, arg_iter);
+    reg_idx++;
+
+    if (GetRegCategoryFromJType(jty) == kRegCat2) {
+      // Wide types
+      reg_idx++;
+    }
+  }
+
+  DCHECK_EQ(arg_iter, func_->arg_end());
+  DCHECK_EQ(reg_idx, num_regs);
+
+  return true;
+}
+
+bool DexLang::EmitPrologueAllcaShadowFrame() {
+  if (!require_shadow_frame) {
+    return true;
+  }
+
+  // Save current IR builder insert point
+  llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP();
+
+  irb_.SetInsertPoint(reg_alloc_bb_);
+  EmitInvokeIntrinsicNoThrow(IntrinsicHelper::AllocaShadowFrame,
+                             irb_.getInt32(num_shadow_frame_entries_));
+
+  // Restore IRBuilder insert point
+  irb_.restoreIP(irb_ip_original);
+
+  return true;
+}
+
+bool DexLang::EmitPrologueLinkBasicBlocks() {
+  irb_.SetInsertPoint(reg_alloc_bb_);
+  irb_.CreateBr(arg_reg_init_bb_);
+  return true;
+}
+
+bool DexLang::PrettyLayoutExceptionBasicBlocks()  {
+  llvm::BasicBlock* last_non_exception_bb = &func_->back();
+  DCHECK(last_non_exception_bb != NULL);
+
+  DCHECK_NE(last_non_exception_bb, exception_unwind_bb_);
+  if (exception_unwind_bb_ != NULL) {
+    exception_unwind_bb_->moveAfter(last_non_exception_bb);
+  }
+
+  for (std::vector<llvm::BasicBlock*>::reverse_iterator
+          landing_pads_bb_iter = landing_pads_bb_.rbegin(),
+          landing_pads_bb_end = landing_pads_bb_.rend();
+       landing_pads_bb_iter != landing_pads_bb_end; landing_pads_bb_iter++) {
+    llvm::BasicBlock* landing_pads_bb = *landing_pads_bb_iter;
+    // Move the successors (the cache handlers) first
+    llvm::TerminatorInst* inst = landing_pads_bb->getTerminator();
+    CHECK(inst != NULL);
+    for (unsigned i = 0, e = inst->getNumSuccessors(); i != e; i++) {
+      llvm::BasicBlock* catch_handler = inst->getSuccessor(i);
+      // One of the catch handler is the unwind basic block which is settled
+      // down earlier
+      if (catch_handler != exception_unwind_bb_) {
+        catch_handler->moveAfter(last_non_exception_bb);
+      }
+    }
+    if (landing_pads_bb != NULL) {
+      DCHECK_NE(last_non_exception_bb, landing_pads_bb);
+      landing_pads_bb->moveAfter(last_non_exception_bb);
+    }
+  }
+
+  return true;
+}
+
+bool DexLang::VerifyFunction() {
+  if (llvm::verifyFunction(*func_, llvm::PrintMessageAction)) {
+    LOG(INFO) << "Verification failed on function: "
+              << PrettyMethod(cunit_.GetDexMethodIndex(), *dex_file_);
+    return false;
+  }
+  return true;
+}
+
+bool DexLang::OptimizeFunction() {
+  // Add optimization pass
+  llvm::FunctionPassManager fpm(&module_);
+
+  fpm.add(llvm::createTypeBasedAliasAnalysisPass());
+  fpm.add(llvm::createBasicAliasAnalysisPass());
+
+  // Perform simple optimizations first to enable the later optimization passes
+  // running fast
+  {
+    fpm.add(llvm::createCFGSimplificationPass());
+
+    // mem2reg
+    fpm.add(llvm::createPromoteMemoryToRegisterPass());
+
+    // Remove redundant instructions
+    fpm.add(llvm::createInstructionSimplifierPass());
+
+    // Fast CSE
+    fpm.add(llvm::createEarlyCSEPass());
+    fpm.add(llvm::createCorrelatedValuePropagationPass());
+
+    // 4 + (x + 5)  ->  x + (4 + 5)
+    fpm.add(llvm::createReassociatePass());
+
+    // Clean up
+    fpm.add(llvm::createCFGSimplificationPass()); // Merge & remove BBs
+    fpm.add(llvm::createInstructionCombiningPass());// Clean up after everything
+  }
+
+  {
+    // SCCP - Sparse conditional constant propagation
+    fpm.add(llvm::createSCCPPass());
+
+    // Global value numbering and redundant load elimination
+    fpm.add(llvm::createGVNPass());
+
+    // Clean up
+    fpm.add(llvm::createCFGSimplificationPass()); // Merge & remove BBs
+    fpm.add(llvm::createInstructionCombiningPass());// Clean up after everything
+  }
+
+  {
+    // Reorders basic blocks to increase the number of fall-through conditional
+    // branches
+    fpm.add(llvm::createBlockPlacementPass());
+
+    // Clean up
+    fpm.add(llvm::createCFGSimplificationPass()); // Merge & remove BBs
+  }
+
+  // DexLang doesn't use static branch prediction in the mean time
+  //fpm.add(llvm::createLowerExpectIntrinsicPass());
+  {
+    // Constant propagation
+    fpm.add(llvm::createConstantPropagationPass());
+
+    // Clean up
+    fpm.add(llvm::createCFGSimplificationPass()); // Merge & remove BBs
+    fpm.add(llvm::createInstructionCombiningPass());// Clean up after everything
+  }
+
+  {
+    // Dead code elimination
+    fpm.add(llvm::createDeadCodeEliminationPass());
+    fpm.add(llvm::createDeadStoreEliminationPass());
+    fpm.add(llvm::createAggressiveDCEPass());
+
+    // Do constant propagation again
+    fpm.add(llvm::createConstantPropagationPass());
+
+    // Clean up
+    fpm.add(llvm::createCFGSimplificationPass()); // Merge & remove BBs
+    fpm.add(llvm::createInstructionCombiningPass());// Clean up after everything
+  }
+
+  // Run the per-function optimization
+  fpm.doInitialization();
+  fpm.run(*func_);
+  fpm.doFinalization();
+
+  return true;
+}
+
+bool DexLang::RemoveRedundantPendingExceptionChecks() {
+#if 0
+  const llvm::Function* exception_checking_function =
+      irb_.GetIntrinsics(IntrinsicHelper::IsExceptionPending);
+
+  std::vector<llvm::Instruction*> work_list;
+
+  unsigned num_removed = 0;
+
+  for (llvm::inst_iterator i = llvm::inst_begin(func_),
+          e = llvm::inst_end(func_); i != e; ++i) {
+    if (llvm::CallInst* call_inst = llvm::dyn_cast<llvm::CallInst>(&*i)) {
+      if (call_inst->getCalledFunction() != exception_checking_function) {
+        continue;
+      }
+    }
+  }
+
+  num_removed = work_list.size();
+
+  for (std::vector<llvm::Instruction*>::iterator inst_iter = work_list.begin(),
+          inst_end = work_list.end(); inst_iter != inst_end; inst_iter++) {
+    llvm::Instruction* inst = *inst_iter;
+    if (!inst->use_empty()) {
+      inst->replaceAllUsesWith(irb_.getFalse());
+    }
+    inst->eraseFromParent();
+  }
+
+  LOG(INFO) << num_removed << " redundant pending exception check removed.";
+#endif
+
+  return true;
+}
+
+//----------------------------------------------------------------------------
+// Emit* Helper Functions
+//----------------------------------------------------------------------------
+llvm::Value* DexLang::EmitLoadMethodObjectAddr() {
+  return func_->arg_begin();
+}
+
+llvm::Value* DexLang::EmitGetCurrentThread() {
+  return EmitInvokeIntrinsicNoThrow(IntrinsicHelper::GetCurrentThread);
+}
+
+llvm::Value*
+DexLang::EmitInvokeIntrinsicNoThrow(IntrinsicHelper::IntrinsicId intr_id) {
+  DCHECK(IntrinsicHelper::GetAttr(intr_id) & IntrinsicHelper::kAttrNoThrow);
+  return irb_.CreateCall(intrinsic_helper_.GetIntrinsicFunction(intr_id));
+}
+
+llvm::Value*
+DexLang::EmitInvokeIntrinsicNoThrow(IntrinsicHelper::IntrinsicId intr_id,
+                                    llvm::ArrayRef<llvm::Value*> args) {
+  llvm::Function* intr = intrinsic_helper_.GetIntrinsicFunction(intr_id);
+  DCHECK(IntrinsicHelper::GetAttr(intr_id) & IntrinsicHelper::kAttrNoThrow);
+  return irb_.CreateCall(intr, args);
+}
+
+llvm::Value*
+DexLang::EmitInvokeIntrinsic(unsigned dex_pc,
+                             IntrinsicHelper::IntrinsicId intr_id) {
+  llvm::Function* intr = intrinsic_helper_.GetIntrinsicFunction(intr_id);
+  unsigned intr_attr = IntrinsicHelper::GetAttr(intr_id);
+  bool may_throw = !(intr_attr & IntrinsicHelper::kAttrNoThrow);
+
+  // Setup PC before invocation when the intrinsics may generate the exception
+  if (may_throw) {
+    EmitUpdateDexPC(dex_pc);
+  }
+
+  llvm::Value* ret_val = irb_.CreateCall(intr);
+
+  if (may_throw) {
+    EmitGuard_ExceptionLandingPad(dex_pc);
+  }
+
+  return ret_val;
+}
+
+llvm::Value* DexLang::EmitInvokeIntrinsic(unsigned dex_pc,
+                                          IntrinsicHelper::IntrinsicId intr_id,
+                                          llvm::ArrayRef<llvm::Value*> args) {
+  llvm::Function* intr = intrinsic_helper_.GetIntrinsicFunction(intr_id);
+  unsigned intr_attr = IntrinsicHelper::GetAttr(intr_id);
+  bool may_throw = !(intr_attr & IntrinsicHelper::kAttrNoThrow);
+
+  // Setup PC before invocation when the intrinsics may generate the exception
+  if (may_throw) {
+    EmitUpdateDexPC(dex_pc);
+  }
+
+  llvm::Value* ret_val = irb_.CreateCall(intr, args);
+
+  if (may_throw) {
+    EmitGuard_ExceptionLandingPad(dex_pc);
+  }
+
+  return ret_val;
+}
+
+RegCategory DexLang::GetInferredRegCategory(unsigned dex_pc, unsigned reg_idx) {
+  Compiler::MethodReference mref(dex_file_, cunit_.GetDexMethodIndex());
+
+  const InferredRegCategoryMap* map =
+    verifier::MethodVerifier::GetInferredRegCategoryMap(mref);
+
+  CHECK_NE(map, static_cast<InferredRegCategoryMap*>(NULL));
+
+  return map->GetRegCategory(dex_pc, reg_idx);
+}
+
+llvm::Value* DexLang::EmitLoadArrayLength(llvm::Value* array) {
+  // Load array length
+  return EmitInvokeIntrinsicNoThrow(IntrinsicHelper::ArrayLength, array);
+}
+
+llvm::Value*
+DexLang::EmitLoadStaticStorage(unsigned dex_pc, unsigned type_idx) {
+  llvm::BasicBlock* block_load_static =
+    CreateBasicBlockWithDexPC(dex_pc, "load_static");
+
+  llvm::BasicBlock* block_cont = CreateBasicBlockWithDexPC(dex_pc, "cont");
+
+  llvm::Constant* type_idx_value = irb_.getInt32(type_idx);
+
+  // Load static storage from dex cache
+  llvm::Value* storage_object_addr =
+      EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::LoadClassSSBFromDexCache,
+                          type_idx_value);
+
+  llvm::BasicBlock* block_original = irb_.GetInsertBlock();
+
+  // Test: Is the static storage of this class initialized?
+  llvm::Value* equal_null =
+    irb_.CreateICmpEQ(storage_object_addr, irb_.GetJNull());
+
+  irb_.CreateCondBr(equal_null, block_load_static, block_cont);
+
+  // Failback routine to load the class object
+  irb_.SetInsertPoint(block_load_static);
+
+  llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+  llvm::Value* thread_object_addr = EmitGetCurrentThread();
+
+  llvm::Value* loaded_storage_object_addr =
+      EmitInvokeIntrinsic3(dex_pc, IntrinsicHelper::InitializeAndLoadClassSSB,
+                           type_idx_value, method_object_addr,
+                           thread_object_addr);
+
+  llvm::BasicBlock* block_after_load_static = irb_.GetInsertBlock();
+
+  irb_.CreateBr(block_cont);
+
+  // Now the class object must be loaded
+  irb_.SetInsertPoint(block_cont);
+
+  llvm::PHINode* phi = irb_.CreatePHI(irb_.GetJObjectTy(), 2);
+
+  phi->addIncoming(storage_object_addr, block_original);
+  phi->addIncoming(loaded_storage_object_addr, block_after_load_static);
+
+  return phi;
+}
+
+llvm::Value* DexLang::EmitConditionResult(llvm::Value* lhs, llvm::Value* rhs,
+                                          CondBranchKind cond) {
+  switch (cond) {
+    case kCondBranch_EQ: {
+      return irb_.CreateICmpEQ(lhs, rhs);
+    }
+    case kCondBranch_NE: {
+      return irb_.CreateICmpNE(lhs, rhs);
+    }
+    case kCondBranch_LT: {
+      return irb_.CreateICmpSLT(lhs, rhs);
+    }
+    case kCondBranch_GE: {
+      return irb_.CreateICmpSGE(lhs, rhs);
+    }
+    case kCondBranch_GT: {
+      return irb_.CreateICmpSGT(lhs, rhs);
+    }
+    case kCondBranch_LE: {
+      return irb_.CreateICmpSLE(lhs, rhs);
+    }
+    default: {
+      // Unreachable
+      LOG(FATAL) << "Unknown conditional branch kind: " << cond;
+      break;
+    }
+  }
+  return NULL;
+}
+
+llvm::Value* DexLang::EmitIntArithmResultComputation(unsigned dex_pc,
+                                                     llvm::Value* lhs,
+                                                     llvm::Value* rhs,
+                                                     IntArithmKind arithm,
+                                                     JType op_jty) {
+  DCHECK((op_jty == kInt) || (op_jty == kLong)) << op_jty;
+
+  switch (arithm) {
+    case kIntArithm_Add: {
+      return irb_.CreateAdd(lhs, rhs);
+    }
+    case kIntArithm_Sub: {
+      return irb_.CreateSub(lhs, rhs);
+    }
+    case kIntArithm_Mul: {
+      return irb_.CreateMul(lhs, rhs);
+    }
+    case kIntArithm_Div:
+    case kIntArithm_Rem: {
+      return EmitIntDivRemResultComputation(dex_pc, lhs, rhs, arithm, op_jty);
+    }
+    case kIntArithm_And: {
+      return irb_.CreateAnd(lhs, rhs);
+    }
+    case kIntArithm_Or: {
+      return irb_.CreateOr(lhs, rhs);
+    }
+    case kIntArithm_Xor: {
+      return irb_.CreateXor(lhs, rhs);
+    }
+    default: {
+      LOG(FATAL) << "Unknown integer arithmetic kind: " << arithm;
+      break;
+    }
+  }
+  return NULL;
+}
+
+llvm::Value* DexLang::EmitIntDivRemResultComputation(unsigned dex_pc,
+                                                     llvm::Value* dividend,
+                                                     llvm::Value* divisor,
+                                                     IntArithmKind arithm,
+                                                     JType op_jty) {
+  // Throw exception if the divisor is 0.
+  EmitGuard_DivZeroException(dex_pc, divisor, op_jty);
+
+  // Note that it's not trivial to translate integer div/rem to sdiv/srem in
+  // LLVM IR since (MININT / -1) leads undefined behavior in LLVM due to
+  // overflow.
+
+  // Select intrinsic
+  bool is_div = (arithm == kIntArithm_Div);
+  IntrinsicHelper::IntrinsicId arithm_intrinsic = IntrinsicHelper::UnknownId;
+  switch (op_jty) {
+    case kInt: {
+      arithm_intrinsic = (is_div) ? IntrinsicHelper::DivInt :
+                                    IntrinsicHelper::RemInt;
+      break;
+    }
+    case kLong: {
+      arithm_intrinsic = (is_div) ? IntrinsicHelper::DivLong :
+                                    IntrinsicHelper::RemLong;
+      break;
+    }
+    default: {
+      LOG(FATAL) << "Unsupported " << ((is_div) ? "div" : "rem") << " operation"
+                    " for type: " << op_jty;
+      return NULL;
+    }
+  }
+
+  return EmitInvokeIntrinsic2(dex_pc, arithm_intrinsic, dividend, divisor);
+}
+
+//----------------------------------------------------------------------------
+// EmitInsn* Functions
+//----------------------------------------------------------------------------
+void DexLang::EmitInsn_Nop(unsigned dex_pc, const Instruction* insn) {
+  uint16_t insn_signature = code_item_->insns_[dex_pc];
+
+  if (insn_signature == Instruction::kPackedSwitchSignature ||
+      insn_signature == Instruction::kSparseSwitchSignature ||
+      insn_signature == Instruction::kArrayDataSignature) {
+    irb_.CreateUnreachable();
+  } else {
+    irb_.CreateBr(GetNextBasicBlock(dex_pc));
+  }
+  return;
+}
+
+void DexLang::EmitInsn_Move(unsigned dex_pc, const Instruction* insn,
+                            JType jty) {
+  DecodedInstruction dec_insn(insn);
+
+  llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, jty, kReg);
+  EmitStoreDalvikReg(dec_insn.vA, jty, kReg, src_value);
+
+  irb_.CreateBr(GetNextBasicBlock(dex_pc));
+  return;
+}
+
+void DexLang::EmitInsn_MoveResult(unsigned dex_pc, const Instruction* insn,
+                                  JType jty) {
+  DecodedInstruction dec_insn(insn);
+
+  CHECK(retval_ != NULL) << "move-result must immediately after an invoke-kind "
+                            "instruction";
+  // Check the type
+  CHECK_EQ(irb_.GetJType(jty, kReg), irb_.GetJType(retval_jty_, kReg))
+      << "Mismatch type between the value from the most recent invoke-kind "
+         "instruction (" << retval_jty_ << ") and the kind of move-result "
+         "used! (" << jty << ")";
+
+  EmitStoreDalvikReg(dec_insn.vA, retval_jty_, kReg, retval_);
+
+  retval_ = NULL;
+
+  irb_.CreateBr(GetNextBasicBlock(dex_pc));
+  return;
+}
+
+void DexLang::EmitInsn_MoveException(unsigned dex_pc, const Instruction* insn) {
+  DecodedInstruction dec_insn(insn);
+
+  llvm::Value* exception_object_addr =
+      EmitInvokeIntrinsicNoThrow(IntrinsicHelper::GetException);
+
+  EmitStoreDalvikReg(dec_insn.vA, kObject, kAccurate, exception_object_addr);
+
+  irb_.CreateBr(GetNextBasicBlock(dex_pc));
+  return;
+}
+
+void DexLang::EmitInsn_ReturnVoid(unsigned dex_pc, const Instruction* insn) {
+  // Garbage collection safe-point
+  EmitGuard_GarbageCollectionSuspend();
+
+  // Pop the shadow frame
+  EmitPopShadowFrame();
+
+  // Return!
+  irb_.CreateRetVoid();
+  return;
+}
+
+void DexLang::EmitInsn_Return(unsigned dex_pc, const Instruction* insn) {
+  DecodedInstruction dec_insn(insn);
+
+  // Garbage collection safe-point
+  EmitGuard_GarbageCollectionSuspend();
+
+  // Pop the shadow frame
+  //
+  // NOTE: It is important to keep this AFTER the GC safe-point.  Otherwise,
+  // the return value might be collected since the shadow stack is popped.
+  EmitPopShadowFrame();
+
+  // Return!
+  char ret_shorty = cunit_.GetShorty()[0];
+  llvm::Value* retval = EmitLoadDalvikReg(dec_insn.vA, ret_shorty, kAccurate);
+
+  irb_.CreateRet(retval);
+  return;
+}
+
+void DexLang::EmitInsn_LoadConstant(unsigned dex_pc, const Instruction* insn,
+                                    JType imm_jty) {
+  DecodedInstruction dec_insn(insn);
+
+  DCHECK(imm_jty == kInt || imm_jty == kLong) << imm_jty;
+
+  int64_t imm = 0;
+
+  switch (insn->Opcode()) {
+    // 32-bit Immediate
+    case Instruction::CONST_4:
+    case Instruction::CONST_16:
+    case Instruction::CONST:
+    case Instruction::CONST_WIDE_16:
+    case Instruction::CONST_WIDE_32: {
+      imm = static_cast<int64_t>(static_cast<int32_t>(dec_insn.vB));
+      break;
+    }
+    case Instruction::CONST_HIGH16: {
+      imm = static_cast<int64_t>(static_cast<int32_t>(
+            static_cast<uint32_t>(static_cast<uint16_t>(dec_insn.vB)) << 16));
+      break;
+    }
+    // 64-bit Immediate
+    case Instruction::CONST_WIDE: {
+      imm = static_cast<int64_t>(dec_insn.vB_wide);
+      break;
+    }
+    case Instruction::CONST_WIDE_HIGH16: {
+      imm = static_cast<int64_t>(
+            static_cast<uint64_t>(static_cast<uint16_t>(dec_insn.vB)) << 48);
+      break;
+    }
+    // Unknown opcode for load constant (unreachable)
+    default: {
+      LOG(FATAL) << "Unknown opcode for load constant: " << insn->Opcode();
+      break;
+    }
+  }
+
+  // Store the non-object register
+  llvm::Type* imm_type = irb_.GetJType(imm_jty, kAccurate);
+  llvm::Constant* imm_value = llvm::ConstantInt::getSigned(imm_type, imm);
+  EmitStoreDalvikReg(dec_insn.vA, imm_jty, kAccurate, imm_value);
+
+  // Store the object register if it is possible to be null.
+  //
+  // FIXME: Should we use GetInferredRegCategory() here to avoid store the value
+  // twice?
+  if (imm_jty == kInt && imm == 0) {
+    EmitStoreDalvikReg(dec_insn.vA, kObject, kAccurate, irb_.GetJNull());
+  }
+
+  irb_.CreateBr(GetNextBasicBlock(dex_pc));
+  return;
+}
+
+void DexLang::EmitInsn_LoadConstantString(unsigned dex_pc,
+                                          const Instruction* insn) {
+  DecodedInstruction dec_insn(insn);
+
+  uint32_t string_idx = dec_insn.vB;
+  llvm::Value* string_idx_value = irb_.getInt32(string_idx);
+  IntrinsicHelper::IntrinsicId intrinsic = IntrinsicHelper::UnknownId;
+
+  if (compiler_.CanAssumeStringIsPresentInDexCache(dex_cache_, string_idx)) {
+    intrinsic = IntrinsicHelper::ConstStringFast;
+  } else {
+    intrinsic = IntrinsicHelper::ConstString;
+  }
+
+  llvm::Value* string_addr =
+      EmitInvokeIntrinsic(dex_pc, intrinsic, string_idx_value);
+
+  EmitStoreDalvikReg(dec_insn.vA, kObject, kAccurate, string_addr);
+
+  irb_.CreateBr(GetNextBasicBlock(dex_pc));
+  return;
+}
+
+void DexLang::EmitInsn_UnconditionalBranch(unsigned dex_pc,
+                                           const Instruction* insn) {
+  DecodedInstruction dec_insn(insn);
+
+  int32_t branch_offset = dec_insn.vA;
+
+  irb_.CreateBr(GetBasicBlock(dex_pc + branch_offset));
+  return;
+}
+
+void DexLang::EmitInsn_ArrayLength(unsigned dex_pc, const Instruction* insn) {
+  DecodedInstruction dec_insn(insn);
+
+  // Get the array object address
+  llvm::Value* array_addr = EmitLoadDalvikReg(dec_insn.vB, kObject, kAccurate);
+
+  // Check whether the array address is null
+  EmitGuard_NullPointerException(dex_pc, array_addr);
+
+  // Get the array length and store it to the register
+  llvm::Value* array_len = EmitLoadArrayLength(array_addr);
+  EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, array_len);
+
+  irb_.CreateBr(GetNextBasicBlock(dex_pc));
+  return;
+}
+
+void DexLang::EmitInsn_NewArray(unsigned dex_pc, const Instruction* insn) {
+  DecodedInstruction dec_insn(insn);
+
+  // Prepare argument to intrinsic
+  llvm::Value* array_length = EmitLoadDalvikReg(dec_insn.vB, kInt, kAccurate);
+  llvm::Value* type_idx = irb_.getInt32(dec_insn.vC);
+
+  llvm::Value* array_addr =
+      EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::NewArray,
+                           array_length, type_idx);
+
+  EmitStoreDalvikReg(dec_insn.vA, kObject, kAccurate, array_addr);
+
+  irb_.CreateBr(GetNextBasicBlock(dex_pc));
+  return;
+}
+
+void DexLang::EmitInsn_UnaryConditionalBranch(unsigned dex_pc,
+                                              const Instruction* insn,
+                                              CondBranchKind cond) {
+  DecodedInstruction dec_insn(insn);
+
+  int8_t src_reg_cat = GetInferredRegCategory(dex_pc, dec_insn.vA);
+
+  DCHECK_NE(kRegUnknown, src_reg_cat);
+  DCHECK_NE(kRegCat2, src_reg_cat);
+
+  int32_t branch_offset = dec_insn.vB;
+
+  llvm::Value* src1_value;
+  llvm::Value* src2_value;
+
+  if (src_reg_cat == kRegZero) {
+    src1_value = irb_.getInt32(0);
+    src2_value = irb_.getInt32(0);
+  } else if (src_reg_cat == kRegCat1nr) {
+    src1_value = EmitLoadDalvikReg(dec_insn.vA, kInt, kReg);
+    src2_value = irb_.getInt32(0);
+  } else {
+    src1_value = EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate);
+    src2_value = irb_.GetJNull();
+  }
+
+  llvm::Value* cond_value = EmitConditionResult(src1_value, src2_value, cond);
+
+  irb_.CreateCondBr(cond_value,
+                    GetBasicBlock(dex_pc + branch_offset),
+                    GetNextBasicBlock(dex_pc));
+  return;
+}
+
+void DexLang::EmitInsn_BinaryConditionalBranch(unsigned dex_pc,
+                                               const Instruction* insn,
+                                               CondBranchKind cond) {
+  DecodedInstruction dec_insn(insn);
+
+  int8_t src1_reg_cat = GetInferredRegCategory(dex_pc, dec_insn.vA);
+  int8_t src2_reg_cat = GetInferredRegCategory(dex_pc, dec_insn.vB);
+
+  DCHECK_NE(kRegUnknown, src1_reg_cat);
+  DCHECK_NE(kRegUnknown, src2_reg_cat);
+  DCHECK_NE(kRegCat2, src1_reg_cat);
+  DCHECK_NE(kRegCat2, src2_reg_cat);
+
+  int32_t branch_offset = dec_insn.vC;
+
+  llvm::Value* src1_value;
+  llvm::Value* src2_value;
+
+  if (src1_reg_cat == kRegZero && src2_reg_cat == kRegZero) {
+    src1_value = irb_.getInt32(0);
+    src2_value = irb_.getInt32(0);
+  } else if (src1_reg_cat != kRegZero && src2_reg_cat != kRegZero) {
+    CHECK_EQ(src1_reg_cat, src2_reg_cat);
+
+    if (src1_reg_cat == kRegCat1nr) {
+      src1_value = EmitLoadDalvikReg(dec_insn.vA, kInt, kAccurate);
+      src2_value = EmitLoadDalvikReg(dec_insn.vB, kInt, kAccurate);
+    } else {
+      src1_value = EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate);
+      src2_value = EmitLoadDalvikReg(dec_insn.vB, kObject, kAccurate);
+    }
+  } else {
+    DCHECK(src1_reg_cat == kRegZero ||
+           src2_reg_cat == kRegZero);
+
+    if (src1_reg_cat == kRegZero) {
+      if (src2_reg_cat == kRegCat1nr) {
+        src1_value = irb_.GetJInt(0);
+        src2_value = EmitLoadDalvikReg(dec_insn.vA, kInt, kAccurate);
+      } else {
+        src1_value = irb_.GetJNull();
+        src2_value = EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate);
+      }
+    } else { // src2_reg_cat == kRegZero
+      if (src2_reg_cat == kRegCat1nr) {
+        src1_value = EmitLoadDalvikReg(dec_insn.vA, kInt, kAccurate);
+        src2_value = irb_.GetJInt(0);
+      } else {
+        src1_value = EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate);
+        src2_value = irb_.GetJNull();
+      }
+    }
+  }
+
+  llvm::Value* cond_value =
+    EmitConditionResult(src1_value, src2_value, cond);
+
+  irb_.CreateCondBr(cond_value,
+                    GetBasicBlock(dex_pc + branch_offset),
+                    GetNextBasicBlock(dex_pc));
+  return;
+}
+
+void DexLang::EmitInsn_AGet(unsigned dex_pc, const Instruction* insn,
+                            JType elem_jty) {
+  DecodedInstruction dec_insn(insn);
+
+  // Select corresponding intrinsic
+  IntrinsicHelper::IntrinsicId aget_intrinsic = IntrinsicHelper::UnknownId;
+
+  switch (elem_jty) {
+    case kInt: {
+      aget_intrinsic = IntrinsicHelper::ArrayGet;
+      break;
+    }
+    case kLong: {
+      aget_intrinsic = IntrinsicHelper::ArrayGetWide;
+      break;
+    }
+    case kObject: {
+      aget_intrinsic = IntrinsicHelper::ArrayGetObject;
+      break;
+    }
+    case kBoolean: {
+      aget_intrinsic = IntrinsicHelper::ArrayGetBoolean;
+      break;
+    }
+    case kByte: {
+      aget_intrinsic = IntrinsicHelper::ArrayGetByte;
+      break;
+    }
+    case kChar: {
+      aget_intrinsic = IntrinsicHelper::ArrayGetChar;
+      break;
+    }
+    case kShort: {
+      aget_intrinsic = IntrinsicHelper::ArrayGetShort;
+      break;
+    }
+    default: {
+      LOG(FATAL) << "Unexpected element type got in aget instruction!";
+      return;
+    }
+  }
+
+  // Construct argument list passed to the intrinsic
+  llvm::Value* array_addr = EmitLoadDalvikReg(dec_insn.vB, kObject, kAccurate);
+  llvm::Value* index_value = EmitLoadDalvikReg(dec_insn.vC, kInt, kAccurate);
+
+  EmitGuard_ArrayException(dex_pc, array_addr, index_value);
+
+  llvm::Value* array_element_value = EmitInvokeIntrinsic2(dex_pc,
+                                                          aget_intrinsic,
+                                                          array_addr,
+                                                          index_value);
+
+  EmitStoreDalvikReg(dec_insn.vA, elem_jty, kArray, array_element_value);
+
+  irb_.CreateBr(GetNextBasicBlock(dex_pc));
+  return;
+}
+
+void DexLang::EmitInsn_APut(unsigned dex_pc, const Instruction* insn,
+                            JType elem_jty) {
+  DecodedInstruction dec_insn(insn);
+
+  // Select corresponding intrinsic
+  IntrinsicHelper::IntrinsicId aput_intrinsic = IntrinsicHelper::UnknownId;
+
+  switch (elem_jty) {
+    case kInt: {
+      aput_intrinsic = IntrinsicHelper::ArrayPut;
+      break;
+    }
+    case kLong: {
+      aput_intrinsic = IntrinsicHelper::ArrayPutWide;
+      break;
+    }
+    case kObject: {
+      aput_intrinsic = IntrinsicHelper::ArrayPutObject;
+      break;
+    }
+    case kBoolean: {
+      aput_intrinsic = IntrinsicHelper::ArrayPutBoolean;
+      break;
+    }
+    case kByte: {
+      aput_intrinsic = IntrinsicHelper::ArrayPutByte;
+      break;
+    }
+    case kChar: {
+      aput_intrinsic = IntrinsicHelper::ArrayPutChar;
+      break;
+    }
+    case kShort: {
+      aput_intrinsic = IntrinsicHelper::ArrayPutShort;
+      break;
+    }
+    default: {
+      LOG(FATAL) << "Unexpected element type got in aput instruction!";
+      return;
+    }
+  }
+
+  // Construct argument list passed to the intrinsic
+  llvm::Value* elem_addr = EmitLoadDalvikReg(dec_insn.vA, elem_jty, kAccurate);
+  llvm::Value* array_addr = EmitLoadDalvikReg(dec_insn.vB, kObject, kAccurate);
+  llvm::Value* index_value = EmitLoadDalvikReg(dec_insn.vC, kInt, kAccurate);
+
+  EmitGuard_ArrayException(dex_pc, array_addr, index_value);
+
+  // Check the type if an object is putting
+  if (elem_jty == kObject) {
+    EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::CheckPutArrayElement,
+                         elem_addr, array_addr);
+  }
+
+  EmitInvokeIntrinsic3(dex_pc, aput_intrinsic,
+                       elem_addr, array_addr, index_value);
+
+  irb_.CreateBr(GetNextBasicBlock(dex_pc));
+
+  return;
+}
+
+void DexLang::EmitInsn_SGet(unsigned dex_pc, const Instruction* insn,
+                            JType field_jty) {
+  DecodedInstruction dec_insn(insn);
+
+  uint32_t field_idx = dec_insn.vB;
+
+  int field_offset;
+  int ssb_index;
+  bool is_referrers_class;
+  bool is_volatile;
+  bool is_fast_path = compiler_.ComputeStaticFieldInfo(field_idx, &cunit_,
+                                                       field_offset, ssb_index,
+                                                       is_referrers_class,
+                                                       is_volatile,
+                                                       /* is_put */true);
+
+  // Select corresponding intrinsic accroding to the field type and is_fast_path
+  IntrinsicHelper::IntrinsicId sget_intrinsic = IntrinsicHelper::UnknownId;
+
+  switch (field_jty) {
+    case kInt: {
+      sget_intrinsic =
+          (is_fast_path) ? IntrinsicHelper::StaticFieldGetFast :
+                           IntrinsicHelper::StaticFieldGet;
+      break;
+    }
+    case kLong: {
+      sget_intrinsic =
+          (is_fast_path) ? IntrinsicHelper::StaticFieldGetWideFast :
+                           IntrinsicHelper::StaticFieldGetWide;
+      break;
+    }
+    case kObject: {
+      sget_intrinsic =
+          (is_fast_path) ? IntrinsicHelper::StaticFieldGetObjectFast :
+                           IntrinsicHelper::StaticFieldGetObject;
+      break;
+    }
+    case kBoolean: {
+      sget_intrinsic =
+          (is_fast_path) ? IntrinsicHelper::StaticFieldGetBooleanFast :
+                           IntrinsicHelper::StaticFieldGetBoolean;
+      break;
+    }
+    case kByte: {
+      sget_intrinsic =
+          (is_fast_path) ? IntrinsicHelper::StaticFieldGetByteFast :
+                           IntrinsicHelper::StaticFieldGetByte;
+      break;
+    }
+    case kChar: {
+      sget_intrinsic =
+          (is_fast_path) ? IntrinsicHelper::StaticFieldGetCharFast :
+                           IntrinsicHelper::StaticFieldGetChar;
+      break;
+    }
+    case kShort: {
+      sget_intrinsic =
+          (is_fast_path) ? IntrinsicHelper::StaticFieldGetShortFast :
+                           IntrinsicHelper::StaticFieldGetShort;
+      break;
+    }
+    default: {
+      LOG(FATAL) << "Unexpected element type got in sget instruction!";
+      return;
+    }
+  }
+
+  llvm::Constant* field_idx_value = irb_.getInt32(field_idx);
+
+  llvm::Value* static_field_value;
+
+  if (!is_fast_path) {
+    llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+    static_field_value =
+        EmitInvokeIntrinsic2(dex_pc, sget_intrinsic,
+                             field_idx_value, method_object_addr);
+  } else {
+    DCHECK_GE(field_offset, 0);
+
+    llvm::Value* static_storage_addr = NULL;
+
+    if (is_referrers_class) {
+      // Fast path, static storage base is this method's class
+      llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+      static_storage_addr =
+        EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::LoadDeclaringClassSSB,
+                            method_object_addr);
+    } else {
+      // Medium path, static storage base in a different class which
+      // requires checks that the other class is initialized
+      DCHECK_GE(ssb_index, 0);
+      static_storage_addr = EmitLoadStaticStorage(dex_pc, ssb_index);
+    }
+
+    static_field_value =
+        EmitInvokeIntrinsic3(dex_pc, sget_intrinsic,
+                             static_storage_addr, irb_.getInt32(field_offset),
+                             irb_.getInt1(is_volatile));
+  }
+
+  EmitStoreDalvikReg(dec_insn.vA, field_jty, kField, static_field_value);
+
+  irb_.CreateBr(GetNextBasicBlock(dex_pc));
+  return;
+}
+
+void DexLang::EmitInsn_SPut(unsigned dex_pc, const Instruction* insn,
+                            JType field_jty) {
+  DecodedInstruction dec_insn(insn);
+
+  uint32_t field_idx = dec_insn.vB;
+
+  llvm::Value* new_value = EmitLoadDalvikReg(dec_insn.vA, field_jty, kField);
+
+  int field_offset;
+  int ssb_index;
+  bool is_referrers_class;
+  bool is_volatile;
+  bool is_fast_path = compiler_.ComputeStaticFieldInfo(field_idx, &cunit_,
+                                                       field_offset, ssb_index,
+                                                       is_referrers_class,
+                                                       is_volatile,
+                                                       /* is_put */true);
+
+  // Select corresponding intrinsic accroding to the field type and is_fast_path
+  IntrinsicHelper::IntrinsicId sput_intrinsic = IntrinsicHelper::UnknownId;
+
+  switch (field_jty) {
+    case kInt: {
+      sput_intrinsic =
+          (is_fast_path) ? IntrinsicHelper::StaticFieldPutFast :
+                           IntrinsicHelper::StaticFieldPut;
+      break;
+    }
+    case kLong: {
+      sput_intrinsic =
+          (is_fast_path) ? IntrinsicHelper::StaticFieldPutWideFast :
+                           IntrinsicHelper::StaticFieldPutWide;
+      break;
+    }
+    case kObject: {
+      sput_intrinsic =
+          (is_fast_path) ? IntrinsicHelper::StaticFieldPutObjectFast :
+                           IntrinsicHelper::StaticFieldPutObject;
+      break;
+    }
+    case kBoolean: {
+      sput_intrinsic =
+          (is_fast_path) ? IntrinsicHelper::StaticFieldPutBooleanFast :
+                           IntrinsicHelper::StaticFieldPutBoolean;
+      break;
+    }
+    case kByte: {
+      sput_intrinsic =
+          (is_fast_path) ? IntrinsicHelper::StaticFieldPutByteFast :
+                           IntrinsicHelper::StaticFieldPutByte;
+      break;
+    }
+    case kChar: {
+      sput_intrinsic =
+          (is_fast_path) ? IntrinsicHelper::StaticFieldPutCharFast :
+                           IntrinsicHelper::StaticFieldPutChar;
+      break;
+    }
+    case kShort: {
+      sput_intrinsic =
+          (is_fast_path) ? IntrinsicHelper::StaticFieldPutShortFast :
+                           IntrinsicHelper::StaticFieldPutShort;
+      break;
+    }
+    default: {
+      LOG(FATAL) << "Unexpected element type got in sput instruction!";
+      return;
+    }
+  }
+
+  if (!is_fast_path) {
+    llvm::Constant* field_idx_value = irb_.getInt32(dec_insn.vB);
+
+    llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+    EmitInvokeIntrinsic3(dex_pc, sput_intrinsic,
+                         field_idx_value, method_object_addr, new_value);
+  } else {
+    DCHECK_GE(field_offset, 0);
+
+    llvm::Value* static_storage_addr = NULL;
+
+    if (is_referrers_class) {
+      // Fast path, static storage base is this method's class
+      llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+      static_storage_addr =
+        EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::LoadDeclaringClassSSB,
+                            method_object_addr);
+    } else {
+      // Medium path, static storage base in a different class which
+      // requires checks that the other class is initialized
+      DCHECK_GE(ssb_index, 0);
+      static_storage_addr = EmitLoadStaticStorage(dex_pc, ssb_index);
+    }
+
+    EmitInvokeIntrinsic4(dex_pc, sput_intrinsic,
+                         static_storage_addr, irb_.getInt32(field_offset),
+                         irb_.getInt1(is_volatile), new_value);
+  }
+
+  irb_.CreateBr(GetNextBasicBlock(dex_pc));
+  return;
+}
+
+void DexLang::EmitInsn_Invoke(unsigned dex_pc, const Instruction* insn,
+                              InvokeType invoke_type, InvokeArgFmt arg_fmt) {
+  DecodedInstruction dec_insn(insn);
+
+  bool is_static = (invoke_type == kStatic);
+  uint32_t callee_method_idx = dec_insn.vB;
+
+  // Compute invoke related information for compiler decision
+  int vtable_idx = -1;
+  uintptr_t direct_code = 0; // Currently unused
+  uintptr_t direct_method = 0;
+  bool is_fast_path = compiler_.ComputeInvokeInfo(callee_method_idx, &cunit_,
+                                                  invoke_type, vtable_idx,
+                                                  direct_code, direct_method);
+
+  // Load *this* actual parameter
+  llvm::Value* this_addr = NULL;
+
+  if (is_static) {
+    this_addr = irb_.GetJNull();
+  } else {
+    // Test: Is *this* parameter equal to null?
+    this_addr = (arg_fmt == kArgReg) ?
+        EmitLoadDalvikReg(dec_insn.arg[0], kObject, kAccurate):
+        EmitLoadDalvikReg(dec_insn.vC + 0, kObject, kAccurate);
+
+    EmitGuard_NullPointerException(dex_pc, this_addr);
+  }
+
+  // Load the method object
+  llvm::Value* callee_method_object_addr = NULL;
+
+  llvm::Value* callee_method_idx_value = irb_.getInt32(callee_method_idx);
+
+  if (!is_fast_path) {
+    llvm::Value* caller_method_object_addr = EmitLoadMethodObjectAddr();
+
+    llvm::Value* thread_object_addr = EmitGetCurrentThread();
+
+    callee_method_object_addr =
+        EmitInvokeIntrinsic5(dex_pc, IntrinsicHelper::GetCalleeMethodObjAddr,
+                             this_addr,
+                             callee_method_idx_value,
+                             caller_method_object_addr,
+                             thread_object_addr,
+                             irb_.getInt32(static_cast<unsigned>(invoke_type)));
+  } else {
+    switch (invoke_type) {
+      case kStatic:
+      case kDirect: {
+        if (direct_method != 0u &&
+            direct_method != static_cast<uintptr_t>(-1)) {
+          callee_method_object_addr =
+            irb_.CreateIntToPtr(irb_.GetPtrEquivInt(direct_method),
+                                irb_.GetJMethodTy());
+        } else {
+          callee_method_object_addr =
+              EmitInvokeIntrinsic(dex_pc,
+                                  IntrinsicHelper::GetSDCalleeMethodObjAddrFast,
+                                  callee_method_idx_value);
+        }
+        break;
+      }
+      case kVirtual: {
+        DCHECK(vtable_idx != -1);
+        callee_method_object_addr =
+            EmitInvokeIntrinsic2(dex_pc,
+                                 IntrinsicHelper::GetVirtualCalleeMethodObjAddrFast,
+                                 irb_.getInt32(vtable_idx), this_addr);
+        break;
+      }
+      case kSuper: {
+        LOG(FATAL) << "invoke-super should be promoted to invoke-direct in "
+                      "the fast path.";
+        break;
+      }
+      case kInterface: {
+        llvm::Value* caller_method_object_addr = EmitLoadMethodObjectAddr();
+
+        llvm::Value* thread_object_addr = EmitGetCurrentThread();
+
+        callee_method_object_addr =
+            EmitInvokeIntrinsic4(dex_pc,
+                                 IntrinsicHelper::GetInterfaceCalleeMethodObjAddrFast,
+                                 this_addr,
+                                 callee_method_idx_value,
+                                 caller_method_object_addr,
+                                 thread_object_addr);
+        break;
+      }
+    }
+  }
+
+  // Get the shorty of the callee
+  uint32_t callee_shorty_size;
+  const DexFile::MethodId& callee_method_id =
+      dex_file_->GetMethodId(callee_method_idx);
+  const char* callee_shorty =
+      dex_file_->GetMethodShorty(callee_method_id, &callee_shorty_size);
+  CHECK_GE(callee_shorty_size, 1u);
+
+  JType callee_ret_jty = GetJTypeFromShorty(callee_shorty[0]);
+
+  // Select the corresponding intrinsic according to the return type
+  IntrinsicHelper::IntrinsicId invoke_intrinsic = IntrinsicHelper::UnknownId;
+
+  if (callee_ret_jty == kVoid) {
+    invoke_intrinsic = IntrinsicHelper::InvokeRetVoid;
+  } else {
+    switch (GetRegCategoryFromJType(callee_ret_jty)) {
+      case kRegCat1nr: {
+        invoke_intrinsic = IntrinsicHelper::InvokeRetCat1;
+        break;
+      }
+      case kRegCat2: {
+        invoke_intrinsic = IntrinsicHelper::InvokeRetCat2;
+        break;
+      }
+      case kRegObject: {
+        invoke_intrinsic = IntrinsicHelper::InvokeRetObject;
+        break;
+      }
+      default: {
+        LOG(FATAL) << "Unknown register category for type: "
+                   << callee_ret_jty;
+        break;
+      }
+    }
+  }
+
+  // Load arguments for invoke intrinsics
+  std::vector<llvm::Value*> args;
+
+  // Callee's method id goes first
+  args.push_back(callee_method_object_addr);
+
+  // Load arguments listing in the dec_insn
+  unsigned arg_idx = 0;
+
+  if (!is_static) {
+    // Push "this" for non-static method
+    args.push_back(this_addr);
+    arg_idx++;
+  }
+
+  // Load argument values according to the shorty
+  for (uint32_t i = 1; i < callee_shorty_size; i++) {
+    unsigned reg_idx = (arg_fmt == kArgReg) ? (dec_insn.vC + arg_idx) :
+                                              (dec_insn.arg[arg_idx]);
+    JType jty = GetJTypeFromShorty(callee_shorty[i]);
+    args.push_back(EmitLoadDalvikReg(reg_idx, jty, kAccurate));
+    arg_idx++;
+
+    if (GetRegCategoryFromJType(jty) == kRegCat2) {
+      // Wide types occupied two registers
+      arg_idx++;
+    }
+  }
+
+  DCHECK_EQ(arg_idx, dec_insn.vA)
+    << "Actual argument mismatch for callee: "
+    << PrettyMethod(callee_method_idx, *dex_file_);
+
+  llvm::Value* retval = EmitInvokeIntrinsic(dex_pc, invoke_intrinsic, args);
+
+  // Store the return value for the subsequent move-result
+  if (callee_shorty[0] != 'V') {
+    retval_ = retval;
+    retval_jty_ = GetJTypeFromShorty(callee_shorty[0]);
+  } else {
+    retval_ = NULL;
+  }
+
+  irb_.CreateBr(GetNextBasicBlock(dex_pc));
+  return;
+}
+
+void DexLang::EmitInsn_IntArithm(unsigned dex_pc, const Instruction* insn,
+                                 IntArithmKind arithm, JType op_jty,
+                                 bool is_2addr) {
+  DecodedInstruction dec_insn(insn);
+
+  DCHECK(op_jty == kInt || op_jty == kLong) << op_jty;
+
+  llvm::Value* src1_value;
+  llvm::Value* src2_value;
+
+  if (is_2addr) {
+    src1_value = EmitLoadDalvikReg(dec_insn.vA, op_jty, kAccurate);
+    src2_value = EmitLoadDalvikReg(dec_insn.vB, op_jty, kAccurate);
+  } else {
+    src1_value = EmitLoadDalvikReg(dec_insn.vB, op_jty, kAccurate);
+    src2_value = EmitLoadDalvikReg(dec_insn.vC, op_jty, kAccurate);
+  }
+
+  llvm::Value* result_value =
+    EmitIntArithmResultComputation(dex_pc, src1_value, src2_value,
+                                   arithm, op_jty);
+
+  EmitStoreDalvikReg(dec_insn.vA, op_jty, kAccurate, result_value);
+
+  irb_.CreateBr(GetNextBasicBlock(dex_pc));
+  return;
+}
+
+void DexLang::EmitInsn_IntArithmImmediate(unsigned dex_pc,
+                                          const Instruction* insn,
+                                          IntArithmKind arithm) {
+  DecodedInstruction dec_insn(insn);
+
+  llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, kInt, kAccurate);
+
+  llvm::Value* imm_value = irb_.getInt32(dec_insn.vC);
+
+  llvm::Value* result_value =
+    EmitIntArithmResultComputation(dex_pc, src_value, imm_value, arithm, kInt);
+
+  EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, result_value);
+
+  irb_.CreateBr(GetNextBasicBlock(dex_pc));
+  return;
+}
+
+void DexLang::EmitInsn_FPArithm(unsigned dex_pc, const Instruction* insn,
+                                FPArithmKind arithm, JType op_jty,
+                                bool is_2addr) {
+  DecodedInstruction dec_insn(insn);
+
+  DCHECK(op_jty == kFloat || op_jty == kDouble) << op_jty;
+
+  llvm::Value* src1_value;
+  llvm::Value* src2_value;
+
+  if (is_2addr) {
+    src1_value = EmitLoadDalvikReg(dec_insn.vA, op_jty, kAccurate);
+    src2_value = EmitLoadDalvikReg(dec_insn.vB, op_jty, kAccurate);
+  } else {
+    src1_value = EmitLoadDalvikReg(dec_insn.vB, op_jty, kAccurate);
+    src2_value = EmitLoadDalvikReg(dec_insn.vC, op_jty, kAccurate);
+  }
+
+  llvm::Value* result_value;
+  switch (arithm) {
+    case kFPArithm_Add: {
+      result_value = irb_.CreateFAdd(src1_value, src2_value);
+      break;
+    }
+    case kFPArithm_Sub: {
+      result_value = irb_.CreateFSub(src1_value, src2_value);
+      break;
+    }
+    case kFPArithm_Mul: {
+      result_value = irb_.CreateFMul(src1_value, src2_value);
+      break;
+    }
+    case kFPArithm_Div: {
+      result_value = irb_.CreateFDiv(src1_value, src2_value);
+      break;
+    }
+    case kFPArithm_Rem: {
+      result_value = irb_.CreateFRem(src1_value, src2_value);
+      break;
+    }
+    default: {
+      LOG(FATAL) << "Unknown floating-point arithmetic kind: " << arithm;
+      return;
+    }
+  }
+
+  EmitStoreDalvikReg(dec_insn.vA, op_jty, kAccurate, result_value);
+
+  irb_.CreateBr(GetNextBasicBlock(dex_pc));
+  return;
+}
+
+bool DexLang::EmitInstructions() {
+  unsigned dex_pc = 0;
+  while (dex_pc < code_item_->insns_size_in_code_units_) {
+    const Instruction* insn = Instruction::At(code_item_->insns_ + dex_pc);
+    if (!EmitInstruction(dex_pc, insn)) {
+      return false;
+    }
+    dex_pc += insn->SizeInCodeUnits();
+  }
+  return true;
+}
+
+bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) {
+  // Set the IRBuilder insertion point
+  irb_.SetInsertPoint(GetBasicBlock(dex_pc));
+
+#define ARGS dex_pc, insn
+
+  // Dispatch the instruction
+  switch (insn->Opcode()) {
+    case Instruction::NOP: {
+      EmitInsn_Nop(ARGS);
+      break;
+    }
+    case Instruction::MOVE:
+    case Instruction::MOVE_FROM16:
+    case Instruction::MOVE_16: {
+      EmitInsn_Move(ARGS, kInt);
+      break;
+    }
+    case Instruction::MOVE_WIDE:
+    case Instruction::MOVE_WIDE_FROM16:
+    case Instruction::MOVE_WIDE_16: {
+      EmitInsn_Move(ARGS, kLong);
+      break;
+    }
+    case Instruction::MOVE_OBJECT:
+    case Instruction::MOVE_OBJECT_FROM16:
+    case Instruction::MOVE_OBJECT_16: {
+      EmitInsn_Move(ARGS, kObject);
+      break;
+    }
+    case Instruction::MOVE_RESULT: {
+      EmitInsn_MoveResult(ARGS, kInt);
+      break;
+    }
+    case Instruction::MOVE_RESULT_WIDE: {
+      EmitInsn_MoveResult(ARGS, kLong);
+      break;
+    }
+    case Instruction::MOVE_RESULT_OBJECT: {
+      EmitInsn_MoveResult(ARGS, kObject);
+      break;
+    }
+    case Instruction::MOVE_EXCEPTION: {
+      EmitInsn_MoveException(ARGS);
+      break;
+    }
+    case Instruction::RETURN_VOID: {
+      EmitInsn_ReturnVoid(ARGS);
+      break;
+    }
+    case Instruction::RETURN:
+    case Instruction::RETURN_WIDE:
+    case Instruction::RETURN_OBJECT: {
+      EmitInsn_Return(ARGS);
+      break;
+    }
+    case Instruction::CONST_4:
+    case Instruction::CONST_16:
+    case Instruction::CONST:
+    case Instruction::CONST_HIGH16: {
+      EmitInsn_LoadConstant(ARGS, kInt);
+      break;
+    }
+    case Instruction::CONST_WIDE_16:
+    case Instruction::CONST_WIDE_32:
+    case Instruction::CONST_WIDE:
+    case Instruction::CONST_WIDE_HIGH16: {
+      EmitInsn_LoadConstant(ARGS, kLong);
+      break;
+    }
+    case Instruction::CONST_STRING:
+    case Instruction::CONST_STRING_JUMBO: {
+      EmitInsn_LoadConstantString(ARGS);
+      break;
+    }
+    case Instruction::CONST_CLASS:
+      //EmitInsn_LoadConstantClass(ARGS);
+      break;
+
+    case Instruction::MONITOR_ENTER:
+      //EmitInsn_MonitorEnter(ARGS);
+      break;
+
+    case Instruction::MONITOR_EXIT:
+      //EmitInsn_MonitorExit(ARGS);
+      break;
+
+    case Instruction::CHECK_CAST:
+      //EmitInsn_CheckCast(ARGS);
+      break;
+
+    case Instruction::INSTANCE_OF:
+      //EmitInsn_InstanceOf(ARGS);
+      break;
+
+    case Instruction::ARRAY_LENGTH: {
+      EmitInsn_ArrayLength(ARGS);
+      break;
+    }
+    case Instruction::NEW_INSTANCE:
+      //EmitInsn_NewInstance(ARGS);
+      break;
+
+    case Instruction::NEW_ARRAY: {
+      EmitInsn_NewArray(ARGS);
+      break;
+    }
+    case Instruction::FILLED_NEW_ARRAY:
+      //EmitInsn_FilledNewArray(ARGS, false);
+      break;
+
+    case Instruction::FILLED_NEW_ARRAY_RANGE:
+      //EmitInsn_FilledNewArray(ARGS, true);
+      break;
+
+    case Instruction::FILL_ARRAY_DATA:
+      //EmitInsn_FillArrayData(ARGS);
+      break;
+
+    case Instruction::THROW:
+      //EmitInsn_ThrowException(ARGS);
+      break;
+
+    case Instruction::GOTO:
+    case Instruction::GOTO_16:
+    case Instruction::GOTO_32: {
+      EmitInsn_UnconditionalBranch(ARGS);
+      break;
+    }
+    case Instruction::PACKED_SWITCH:
+      //EmitInsn_PackedSwitch(ARGS);
+      break;
+
+    case Instruction::SPARSE_SWITCH:
+      //EmitInsn_SparseSwitch(ARGS);
+      break;
+
+    case Instruction::CMPL_FLOAT:
+      //EmitInsn_FPCompare(ARGS, kFloat, false);
+      break;
+
+    case Instruction::CMPG_FLOAT:
+      //EmitInsn_FPCompare(ARGS, kFloat, true);
+      break;
+
+    case Instruction::CMPL_DOUBLE:
+      //EmitInsn_FPCompare(ARGS, kDouble, false);
+      break;
+
+    case Instruction::CMPG_DOUBLE:
+      //EmitInsn_FPCompare(ARGS, kDouble, true);
+      break;
+
+    case Instruction::CMP_LONG:
+      //EmitInsn_LongCompare(ARGS);
+      break;
+
+    case Instruction::IF_EQ: {
+      EmitInsn_BinaryConditionalBranch(ARGS, kCondBranch_EQ);
+      break;
+    }
+    case Instruction::IF_NE: {
+      EmitInsn_BinaryConditionalBranch(ARGS, kCondBranch_NE);
+      break;
+    }
+    case Instruction::IF_LT: {
+      EmitInsn_BinaryConditionalBranch(ARGS, kCondBranch_LT);
+      break;
+    }
+    case Instruction::IF_GE: {
+      EmitInsn_BinaryConditionalBranch(ARGS, kCondBranch_GE);
+      break;
+    }
+    case Instruction::IF_GT: {
+      EmitInsn_BinaryConditionalBranch(ARGS, kCondBranch_GT);
+      break;
+    }
+    case Instruction::IF_LE: {
+      EmitInsn_BinaryConditionalBranch(ARGS, kCondBranch_LE);
+      break;
+    }
+    case Instruction::IF_EQZ: {
+      EmitInsn_UnaryConditionalBranch(ARGS, kCondBranch_EQ);
+      break;
+    }
+    case Instruction::IF_NEZ: {
+      EmitInsn_UnaryConditionalBranch(ARGS, kCondBranch_NE);
+      break;
+    }
+    case Instruction::IF_LTZ: {
+      EmitInsn_UnaryConditionalBranch(ARGS, kCondBranch_LT);
+      break;
+    }
+    case Instruction::IF_GEZ: {
+      EmitInsn_UnaryConditionalBranch(ARGS, kCondBranch_GE);
+      break;
+    }
+    case Instruction::IF_GTZ: {
+      EmitInsn_UnaryConditionalBranch(ARGS, kCondBranch_GT);
+      break;
+    }
+    case Instruction::IF_LEZ: {
+      EmitInsn_UnaryConditionalBranch(ARGS, kCondBranch_LE);
+      break;
+    }
+    case Instruction::AGET: {
+      EmitInsn_AGet(ARGS, kInt);
+      break;
+    }
+    case Instruction::AGET_WIDE: {
+      EmitInsn_AGet(ARGS, kLong);
+      break;
+    }
+    case Instruction::AGET_OBJECT: {
+      EmitInsn_AGet(ARGS, kObject);
+      break;
+    }
+    case Instruction::AGET_BOOLEAN: {
+      EmitInsn_AGet(ARGS, kBoolean);
+      break;
+    }
+    case Instruction::AGET_BYTE: {
+      EmitInsn_AGet(ARGS, kByte);
+      break;
+    }
+    case Instruction::AGET_CHAR: {
+      EmitInsn_AGet(ARGS, kChar);
+      break;
+    }
+    case Instruction::AGET_SHORT: {
+      EmitInsn_AGet(ARGS, kShort);
+      break;
+    }
+    case Instruction::APUT: {
+      EmitInsn_APut(ARGS, kInt);
+      break;
+    }
+    case Instruction::APUT_WIDE: {
+      EmitInsn_APut(ARGS, kLong);
+      break;
+    }
+    case Instruction::APUT_OBJECT: {
+      EmitInsn_APut(ARGS, kObject);
+      break;
+    }
+    case Instruction::APUT_BOOLEAN: {
+      EmitInsn_APut(ARGS, kBoolean);
+      break;
+    }
+    case Instruction::APUT_BYTE: {
+      EmitInsn_APut(ARGS, kByte);
+      break;
+    }
+    case Instruction::APUT_CHAR: {
+      EmitInsn_APut(ARGS, kChar);
+      break;
+    }
+    case Instruction::APUT_SHORT: {
+      EmitInsn_APut(ARGS, kShort);
+      break;
+    }
+    case Instruction::IGET:
+      //EmitInsn_IGet(ARGS, kInt);
+      break;
+
+    case Instruction::IGET_WIDE:
+      //EmitInsn_IGet(ARGS, kLong);
+      break;
+
+    case Instruction::IGET_OBJECT:
+      //EmitInsn_IGet(ARGS, kObject);
+      break;
+
+    case Instruction::IGET_BOOLEAN:
+      //EmitInsn_IGet(ARGS, kBoolean);
+      break;
+
+    case Instruction::IGET_BYTE:
+      //EmitInsn_IGet(ARGS, kByte);
+      break;
+
+    case Instruction::IGET_CHAR:
+      //EmitInsn_IGet(ARGS, kChar);
+      break;
+
+    case Instruction::IGET_SHORT:
+      //EmitInsn_IGet(ARGS, kShort);
+      break;
+
+    case Instruction::IPUT:
+      //EmitInsn_IPut(ARGS, kInt);
+      break;
+
+    case Instruction::IPUT_WIDE:
+      //EmitInsn_IPut(ARGS, kLong);
+      break;
+
+    case Instruction::IPUT_OBJECT:
+      //EmitInsn_IPut(ARGS, kObject);
+      break;
+
+    case Instruction::IPUT_BOOLEAN:
+      //EmitInsn_IPut(ARGS, kBoolean);
+      break;
+
+    case Instruction::IPUT_BYTE:
+      //EmitInsn_IPut(ARGS, kByte);
+      break;
+
+    case Instruction::IPUT_CHAR:
+      //EmitInsn_IPut(ARGS, kChar);
+      break;
+
+    case Instruction::IPUT_SHORT:
+      //EmitInsn_IPut(ARGS, kShort);
+      break;
+
+    case Instruction::SGET: {
+      EmitInsn_SGet(ARGS, kInt);
+      break;
+    }
+    case Instruction::SGET_WIDE: {
+      EmitInsn_SGet(ARGS, kLong);
+      break;
+    }
+    case Instruction::SGET_OBJECT: {
+      EmitInsn_SGet(ARGS, kObject);
+      break;
+    }
+    case Instruction::SGET_BOOLEAN: {
+      EmitInsn_SGet(ARGS, kBoolean);
+      break;
+    }
+    case Instruction::SGET_BYTE: {
+      EmitInsn_SGet(ARGS, kByte);
+      break;
+    }
+    case Instruction::SGET_CHAR: {
+      EmitInsn_SGet(ARGS, kChar);
+      break;
+    }
+    case Instruction::SGET_SHORT: {
+      EmitInsn_SGet(ARGS, kShort);
+      break;
+    }
+    case Instruction::SPUT: {
+      EmitInsn_SPut(ARGS, kInt);
+      break;
+    }
+    case Instruction::SPUT_WIDE: {
+      EmitInsn_SPut(ARGS, kLong);
+      break;
+    }
+    case Instruction::SPUT_OBJECT: {
+      EmitInsn_SPut(ARGS, kObject);
+      break;
+    }
+    case Instruction::SPUT_BOOLEAN: {
+      EmitInsn_SPut(ARGS, kBoolean);
+      break;
+    }
+    case Instruction::SPUT_BYTE: {
+      EmitInsn_SPut(ARGS, kByte);
+      break;
+    }
+    case Instruction::SPUT_CHAR: {
+      EmitInsn_SPut(ARGS, kChar);
+      break;
+    }
+    case Instruction::SPUT_SHORT: {
+      EmitInsn_SPut(ARGS, kShort);
+      break;
+    }
+    case Instruction::INVOKE_VIRTUAL: {
+      EmitInsn_Invoke(ARGS, kVirtual, kArgReg);
+      break;
+    }
+    case Instruction::INVOKE_SUPER: {
+      EmitInsn_Invoke(ARGS, kSuper, kArgReg);
+      break;
+    }
+    case Instruction::INVOKE_DIRECT: {
+      EmitInsn_Invoke(ARGS, kDirect, kArgReg);
+      break;
+    }
+    case Instruction::INVOKE_STATIC: {
+      EmitInsn_Invoke(ARGS, kStatic, kArgReg);
+      break;
+    }
+    case Instruction::INVOKE_INTERFACE: {
+      EmitInsn_Invoke(ARGS, kInterface, kArgReg);
+      break;
+    }
+    case Instruction::INVOKE_VIRTUAL_RANGE: {
+      EmitInsn_Invoke(ARGS, kVirtual, kArgRange);
+      break;
+    }
+    case Instruction::INVOKE_SUPER_RANGE: {
+      EmitInsn_Invoke(ARGS, kSuper, kArgRange);
+      break;
+    }
+    case Instruction::INVOKE_DIRECT_RANGE: {
+      EmitInsn_Invoke(ARGS, kDirect, kArgRange);
+      break;
+    }
+    case Instruction::INVOKE_STATIC_RANGE: {
+      EmitInsn_Invoke(ARGS, kStatic, kArgRange);
+      break;
+    }
+    case Instruction::INVOKE_INTERFACE_RANGE: {
+      EmitInsn_Invoke(ARGS, kInterface, kArgRange);
+      break;
+    }
+    case Instruction::NEG_INT:
+      //EmitInsn_Neg(ARGS, kInt);
+      break;
+
+    case Instruction::NOT_INT:
+      //EmitInsn_Not(ARGS, kInt);
+      break;
+
+    case Instruction::NEG_LONG:
+      //EmitInsn_Neg(ARGS, kLong);
+      break;
+
+    case Instruction::NOT_LONG:
+      //EmitInsn_Not(ARGS, kLong);
+      break;
+
+    case Instruction::NEG_FLOAT:
+      //EmitInsn_FNeg(ARGS, kFloat);
+      break;
+
+    case Instruction::NEG_DOUBLE:
+      //EmitInsn_FNeg(ARGS, kDouble);
+      break;
+
+    case Instruction::INT_TO_LONG:
+      //EmitInsn_SExt(ARGS);
+      break;
+
+    case Instruction::INT_TO_FLOAT:
+      //EmitInsn_IntToFP(ARGS, kInt, kFloat);
+      break;
+
+    case Instruction::INT_TO_DOUBLE:
+      //EmitInsn_IntToFP(ARGS, kInt, kDouble);
+      break;
+
+    case Instruction::LONG_TO_INT:
+      //EmitInsn_Trunc(ARGS);
+      break;
+
+    case Instruction::LONG_TO_FLOAT:
+      //EmitInsn_IntToFP(ARGS, kLong, kFloat);
+      break;
+
+    case Instruction::LONG_TO_DOUBLE:
+      //EmitInsn_IntToFP(ARGS, kLong, kDouble);
+      break;
+
+    case Instruction::FLOAT_TO_INT:
+      //EmitInsn_FPToInt(ARGS, kFloat, kInt, F2I);
+      break;
+
+    case Instruction::FLOAT_TO_LONG:
+      //EmitInsn_FPToInt(ARGS, kFloat, kLong, F2L);
+      break;
+
+    case Instruction::FLOAT_TO_DOUBLE:
+      //EmitInsn_FExt(ARGS);
+      break;
+
+    case Instruction::DOUBLE_TO_INT:
+      //EmitInsn_FPToInt(ARGS, kDouble, kInt, D2I);
+      break;
+
+    case Instruction::DOUBLE_TO_LONG:
+      //EmitInsn_FPToInt(ARGS, kDouble, kLong, D2L);
+      break;
+
+    case Instruction::DOUBLE_TO_FLOAT:
+      //EmitInsn_FTrunc(ARGS);
+      break;
+
+    case Instruction::INT_TO_BYTE:
+      //EmitInsn_TruncAndSExt(ARGS, 8);
+      break;
+
+    case Instruction::INT_TO_CHAR:
+      //EmitInsn_TruncAndZExt(ARGS, 16);
+      break;
+
+    case Instruction::INT_TO_SHORT:
+      //EmitInsn_TruncAndSExt(ARGS, 16);
+      break;
+
+    case Instruction::ADD_INT: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Add, kInt, false);
+      break;
+    }
+    case Instruction::SUB_INT: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Sub, kInt, false);
+      break;
+    }
+    case Instruction::MUL_INT: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Mul, kInt, false);
+      break;
+    }
+    case Instruction::DIV_INT: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Div, kInt, false);
+      break;
+    }
+    case Instruction::REM_INT: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Rem, kInt, false);
+      break;
+    }
+    case Instruction::AND_INT: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_And, kInt, false);
+      break;
+    }
+    case Instruction::OR_INT: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Or, kInt, false);
+      break;
+    }
+    case Instruction::XOR_INT: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Xor, kInt, false);
+      break;
+    }
+    case Instruction::SHL_INT:
+      //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kInt, false);
+      break;
+
+    case Instruction::SHR_INT:
+      //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kInt, false);
+      break;
+
+    case Instruction::USHR_INT:
+      //EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kInt, false);
+      break;
+
+    case Instruction::ADD_LONG: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Add, kLong, false);
+      break;
+    }
+    case Instruction::SUB_LONG: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Sub, kLong, false);
+      break;
+    }
+    case Instruction::MUL_LONG: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Mul, kLong, false);
+      break;
+    }
+    case Instruction::DIV_LONG: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Div, kLong, false);
+      break;
+    }
+    case Instruction::REM_LONG: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Rem, kLong, false);
+      break;
+    }
+    case Instruction::AND_LONG: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_And, kLong, false);
+      break;
+    }
+    case Instruction::OR_LONG: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Or, kLong, false);
+      break;
+    }
+    case Instruction::XOR_LONG: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Xor, kLong, false);
+      break;
+    }
+    case Instruction::SHL_LONG:
+      //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kLong, false);
+      break;
+
+    case Instruction::SHR_LONG:
+      //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kLong, false);
+      break;
+
+    case Instruction::USHR_LONG:
+      //EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kLong, false);
+      break;
+
+    case Instruction::ADD_FLOAT: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Add, kFloat, false);
+      break;
+    }
+    case Instruction::SUB_FLOAT: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Sub, kFloat, false);
+      break;
+    }
+    case Instruction::MUL_FLOAT: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Mul, kFloat, false);
+      break;
+    }
+    case Instruction::DIV_FLOAT: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Div, kFloat, false);
+      break;
+    }
+    case Instruction::REM_FLOAT: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Rem, kFloat, false);
+      break;
+    }
+    case Instruction::ADD_DOUBLE: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Add, kDouble, false);
+      break;
+    }
+    case Instruction::SUB_DOUBLE: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Sub, kDouble, false);
+      break;
+    }
+    case Instruction::MUL_DOUBLE: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Mul, kDouble, false);
+      break;
+    }
+    case Instruction::DIV_DOUBLE: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Div, kDouble, false);
+      break;
+    }
+    case Instruction::REM_DOUBLE: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Rem, kDouble, false);
+      break;
+    }
+    case Instruction::ADD_INT_2ADDR: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Add, kInt, true);
+      break;
+    }
+    case Instruction::SUB_INT_2ADDR: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Sub, kInt, true);
+      break;
+    }
+    case Instruction::MUL_INT_2ADDR: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Mul, kInt, true);
+      break;
+    }
+    case Instruction::DIV_INT_2ADDR: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Div, kInt, true);
+      break;
+    }
+    case Instruction::REM_INT_2ADDR: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Rem, kInt, true);
+      break;
+    }
+    case Instruction::AND_INT_2ADDR: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_And, kInt, true);
+      break;
+    }
+    case Instruction::OR_INT_2ADDR: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Or, kInt, true);
+      break;
+    }
+    case Instruction::XOR_INT_2ADDR: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Xor, kInt, true);
+      break;
+    }
+    case Instruction::SHL_INT_2ADDR:
+      //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kInt, true);
+      break;
+
+    case Instruction::SHR_INT_2ADDR:
+      //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kInt, true);
+      break;
+
+    case Instruction::USHR_INT_2ADDR:
+      //EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kInt, true);
+      break;
+
+    case Instruction::ADD_LONG_2ADDR: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Add, kLong, true);
+      break;
+    }
+    case Instruction::SUB_LONG_2ADDR: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Sub, kLong, true);
+      break;
+    }
+    case Instruction::MUL_LONG_2ADDR: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Mul, kLong, true);
+      break;
+    }
+    case Instruction::DIV_LONG_2ADDR: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Div, kLong, true);
+      break;
+    }
+    case Instruction::REM_LONG_2ADDR: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Rem, kLong, true);
+      break;
+    }
+    case Instruction::AND_LONG_2ADDR: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_And, kLong, true);
+      break;
+    }
+    case Instruction::OR_LONG_2ADDR: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Or, kLong, true);
+      break;
+    }
+    case Instruction::XOR_LONG_2ADDR: {
+      EmitInsn_IntArithm(ARGS, kIntArithm_Xor, kLong, true);
+      break;
+    }
+    case Instruction::SHL_LONG_2ADDR:
+      //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kLong, true);
+      break;
+
+    case Instruction::SHR_LONG_2ADDR:
+      //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kLong, true);
+      break;
+
+    case Instruction::USHR_LONG_2ADDR:
+      //EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kLong, true);
+      break;
+
+    case Instruction::ADD_FLOAT_2ADDR: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Add, kFloat, true);
+      break;
+    }
+    case Instruction::SUB_FLOAT_2ADDR: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Sub, kFloat, true);
+      break;
+    }
+    case Instruction::MUL_FLOAT_2ADDR: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Mul, kFloat, true);
+      break;
+    }
+    case Instruction::DIV_FLOAT_2ADDR: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Div, kFloat, true);
+      break;
+    }
+    case Instruction::REM_FLOAT_2ADDR: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Rem, kFloat, true);
+      break;
+    }
+    case Instruction::ADD_DOUBLE_2ADDR: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Add, kDouble, true);
+      break;
+    }
+    case Instruction::SUB_DOUBLE_2ADDR: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Sub, kDouble, true);
+      break;
+    }
+    case Instruction::MUL_DOUBLE_2ADDR: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Mul, kDouble, true);
+      break;
+    }
+    case Instruction::DIV_DOUBLE_2ADDR: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Div, kDouble, true);
+      break;
+    }
+    case Instruction::REM_DOUBLE_2ADDR: {
+      EmitInsn_FPArithm(ARGS, kFPArithm_Rem, kDouble, true);
+      break;
+    }
+    case Instruction::ADD_INT_LIT16:
+    case Instruction::ADD_INT_LIT8: {
+      EmitInsn_IntArithmImmediate(ARGS, kIntArithm_Add);
+      break;
+    }
+    case Instruction::RSUB_INT:
+    case Instruction::RSUB_INT_LIT8:
+      //EmitInsn_RSubImmediate(ARGS);
+      break;
+
+    case Instruction::MUL_INT_LIT16:
+    case Instruction::MUL_INT_LIT8: {
+      EmitInsn_IntArithmImmediate(ARGS, kIntArithm_Mul);
+      break;
+    }
+    case Instruction::DIV_INT_LIT16:
+    case Instruction::DIV_INT_LIT8: {
+      EmitInsn_IntArithmImmediate(ARGS, kIntArithm_Div);
+      break;
+    }
+    case Instruction::REM_INT_LIT16:
+    case Instruction::REM_INT_LIT8: {
+      EmitInsn_IntArithmImmediate(ARGS, kIntArithm_Rem);
+      break;
+    }
+    case Instruction::AND_INT_LIT16:
+    case Instruction::AND_INT_LIT8: {
+      EmitInsn_IntArithmImmediate(ARGS, kIntArithm_And);
+      break;
+    }
+    case Instruction::OR_INT_LIT16:
+    case Instruction::OR_INT_LIT8: {
+      EmitInsn_IntArithmImmediate(ARGS, kIntArithm_Or);
+      break;
+    }
+    case Instruction::XOR_INT_LIT16:
+    case Instruction::XOR_INT_LIT8: {
+      EmitInsn_IntArithmImmediate(ARGS, kIntArithm_Xor);
+      break;
+    }
+    case Instruction::SHL_INT_LIT8:
+      //EmitInsn_IntShiftArithmImmediate(ARGS, kIntArithm_Shl);
+      break;
+
+    case Instruction::SHR_INT_LIT8:
+      //EmitInsn_IntShiftArithmImmediate(ARGS, kIntArithm_Shr);
+      break;
+
+    case Instruction::USHR_INT_LIT8:
+      //EmitInsn_IntShiftArithmImmediate(ARGS, kIntArithm_UShr);
+      break;
+
+    case Instruction::THROW_VERIFICATION_ERROR:
+      //EmitInsn_ThrowVerificationError(ARGS);
+      break;
+    case Instruction::UNUSED_3E:
+    case Instruction::UNUSED_3F:
+    case Instruction::UNUSED_40:
+    case Instruction::UNUSED_41:
+    case Instruction::UNUSED_42:
+    case Instruction::UNUSED_43:
+    case Instruction::UNUSED_73:
+    case Instruction::UNUSED_79:
+    case Instruction::UNUSED_7A:
+    case Instruction::UNUSED_E3:
+    case Instruction::UNUSED_E4:
+    case Instruction::UNUSED_E5:
+    case Instruction::UNUSED_E6:
+    case Instruction::UNUSED_E7:
+    case Instruction::UNUSED_E8:
+    case Instruction::UNUSED_E9:
+    case Instruction::UNUSED_EA:
+    case Instruction::UNUSED_EB:
+    case Instruction::UNUSED_EC:
+    case Instruction::UNUSED_EE:
+    case Instruction::UNUSED_EF:
+    case Instruction::UNUSED_F0:
+    case Instruction::UNUSED_F1:
+    case Instruction::UNUSED_F2:
+    case Instruction::UNUSED_F3:
+    case Instruction::UNUSED_F4:
+    case Instruction::UNUSED_F5:
+    case Instruction::UNUSED_F6:
+    case Instruction::UNUSED_F7:
+    case Instruction::UNUSED_F8:
+    case Instruction::UNUSED_F9:
+    case Instruction::UNUSED_FA:
+    case Instruction::UNUSED_FB:
+    case Instruction::UNUSED_FC:
+    case Instruction::UNUSED_FD:
+    case Instruction::UNUSED_FE:
+    case Instruction::UNUSED_FF: {
+      LOG(FATAL) << "Dex file contains UNUSED bytecode: " << insn->Opcode();
+    }
+  }
+#undef ARGS
+
+  return true;
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/dex_lang.h b/src/greenland/dex_lang.h
new file mode 100644
index 0000000..27b50dd
--- /dev/null
+++ b/src/greenland/dex_lang.h
@@ -0,0 +1,495 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_DEX_LANG_H_
+#define ART_SRC_GREENLAND_DEX_LANG_H_
+
+#include "backend_types.h"
+#include "dalvik_reg.h"
+#include "ir_builder.h"
+
+#include "dex_file.h"
+#include "dex_instruction.h"
+#include "invoke_type.h"
+#include "macros.h"
+
+#include <vector>
+
+#include <llvm/LLVMContext.h>
+#include <llvm/ADT/ArrayRef.h>
+
+namespace llvm {
+  class BasicBlock;
+  class Function;
+  class LLVMContext;
+  class Module;
+  class Type;
+}
+
+namespace art {
+  class Compiler;
+  class OatCompilationUnit;
+}
+
+namespace art {
+namespace greenland {
+
+class DalvikReg;
+class IntrinsicHelper;
+
+class DexLang {
+ public:
+  class Context {
+   private:
+    llvm::LLVMContext context_;
+    llvm::Module* module_;
+    IntrinsicHelper* intrinsic_helper_;
+
+    volatile int32_t ref_count_;
+    volatile int32_t mem_usage_;
+
+    ~Context();
+
+    DISALLOW_COPY_AND_ASSIGN(Context);
+
+   public:
+    Context();
+
+    inline llvm::LLVMContext& GetLLVMContext()
+    { return context_; }
+    inline llvm::Module& GetOutputModule()
+    { return *module_; }
+    inline IntrinsicHelper& GetIntrinsicHelper()
+    { return *intrinsic_helper_; }
+
+    Context& IncRef();
+    void DecRef();
+
+    void AddMemUsageApproximation(size_t usage);
+    inline bool IsMemUsageThresholdReached() const {
+      return (mem_usage_ > (30 << 20)); // (threshold: 30MiB)
+    }
+  };
+
+ public:
+  DexLang(Context& context, Compiler& compiler, OatCompilationUnit& cunit);
+
+  ~DexLang();
+
+  llvm::Function* Build();
+
+  inline IRBuilder& GetIRBuilder() {
+    return irb_;
+  }
+  llvm::Value* AllocateDalvikReg(JType jty, unsigned reg_idx);
+
+ private:
+  Context& dex_lang_ctx_;
+  Compiler& compiler_;
+  OatCompilationUnit& cunit_;
+
+  const DexFile* dex_file_;
+  const DexFile::CodeItem* code_item_;
+  DexCache* dex_cache_;
+
+  llvm::LLVMContext& context_;
+  llvm::Module& module_;
+  IntrinsicHelper& intrinsic_helper_;
+
+  IRBuilder irb_;
+  llvm::Function* func_;
+
+ private:
+  //----------------------------------------------------------------------------
+  // Basic Block Helper Functions
+  //----------------------------------------------------------------------------
+  llvm::BasicBlock* reg_alloc_bb_;
+  llvm::BasicBlock* arg_reg_init_bb_;
+
+  std::vector<llvm::BasicBlock*> basic_blocks_;
+
+  llvm::BasicBlock* GetBasicBlock(unsigned dex_pc);
+  llvm::BasicBlock* CreateBasicBlockWithDexPC(unsigned dex_pc,
+                                              char const* postfix = NULL);
+  llvm::BasicBlock* GetNextBasicBlock(unsigned dex_pc);
+
+ private:
+  //----------------------------------------------------------------------------
+  // Register Helper Functions
+  //----------------------------------------------------------------------------
+  std::vector<DalvikReg*> regs_;
+
+  inline llvm::Value* EmitLoadDalvikReg(unsigned reg_idx, JType jty,
+                                        JTypeSpace space) {
+    DCHECK(regs_.at(reg_idx) != NULL);
+    return regs_[reg_idx]->GetValue(jty, space);
+  }
+
+  inline llvm::Value* EmitLoadDalvikReg(unsigned reg_idx, char shorty,
+                                        JTypeSpace space) {
+    DCHECK(regs_.at(reg_idx) != NULL);
+    return EmitLoadDalvikReg(reg_idx, GetJTypeFromShorty(shorty), space);
+  }
+
+  inline void EmitStoreDalvikReg(unsigned reg_idx, JType jty, JTypeSpace space,
+                                 llvm::Value* new_value) {
+    regs_[reg_idx]->SetValue(jty, space, new_value);
+    return;
+  }
+
+  inline void EmitStoreDalvikReg(unsigned reg_idx, char shorty,
+                                 JTypeSpace space, llvm::Value* new_value) {
+    EmitStoreDalvikReg(reg_idx, GetJTypeFromShorty(shorty), space, new_value);
+    return;
+  }
+
+ private:
+  //----------------------------------------------------------------------------
+  // Return Value Related
+  //----------------------------------------------------------------------------
+  // Hold the return value returned from the lastest invoke-* instruction
+  llvm::Value* retval_;
+  // The type of ret_val_
+  JType retval_jty_;
+
+ private:
+  //----------------------------------------------------------------------------
+  // Exception Handling
+  //----------------------------------------------------------------------------
+  std::vector<llvm::BasicBlock*> landing_pads_bb_;
+  llvm::BasicBlock* exception_unwind_bb_;
+
+  // cur_try_item_offset caches the latest try item offset such that we don't
+  // have to call DexFile::FindCatchHandlerOffset(...) (using binary search) for
+  // every query of the try item for the given dex_pc.
+  int32_t cur_try_item_offset;
+
+  int32_t GetTryItemOffset(unsigned dex_pc);
+
+  llvm::BasicBlock* GetLandingPadBasicBlock(unsigned dex_pc);
+
+  llvm::BasicBlock* GetUnwindBasicBlock();
+
+  void EmitBranchExceptionLandingPad(unsigned dex_pc);
+
+  void EmitGuard_DivZeroException(unsigned dex_pc,
+                                  llvm::Value* denominator,
+                                  JType op_jty);
+
+  void EmitGuard_NullPointerException(unsigned dex_pc, llvm::Value* object);
+
+  void EmitGuard_ArrayIndexOutOfBoundsException(unsigned dex_pc,
+                                                llvm::Value* array,
+                                                llvm::Value* index);
+
+  void EmitGuard_ArrayException(unsigned dex_pc,
+                                llvm::Value* array,
+                                llvm::Value* index);
+
+  void EmitGuard_ExceptionLandingPad(unsigned dex_pc);
+
+ private:
+  //----------------------------------------------------------------------------
+  // Garbage Collection Safe Point
+  //----------------------------------------------------------------------------
+  void EmitGuard_GarbageCollectionSuspend();
+
+ private:
+  //----------------------------------------------------------------------------
+  // Shadow Frame
+  //----------------------------------------------------------------------------
+  bool require_shadow_frame;
+  unsigned num_shadow_frame_entries_;
+
+  void EmitUpdateDexPC(unsigned dex_pc);
+
+  void EmitPopShadowFrame();
+
+ public:
+  unsigned AllocShadowFrameEntry(unsigned reg_idx);
+
+ private:
+  //----------------------------------------------------------------------------
+  // Code Generation
+  //----------------------------------------------------------------------------
+  bool CreateFunction();
+  llvm::FunctionType* GetFunctionType();
+
+  bool PrepareDalvikRegs();
+
+  bool EmitPrologue();
+  bool EmitPrologueAssignArgRegister();
+  bool EmitPrologueAllcaShadowFrame();
+  bool EmitPrologueLinkBasicBlocks();
+  bool PrettyLayoutExceptionBasicBlocks();
+  bool VerifyFunction();
+  bool OptimizeFunction();
+  // Our optimization passes
+  bool RemoveRedundantPendingExceptionChecks();
+
+  //----------------------------------------------------------------------------
+  // Emit* Helper Functions
+  //----------------------------------------------------------------------------
+  enum CondBranchKind {
+    kCondBranch_EQ,
+    kCondBranch_NE,
+    kCondBranch_LT,
+    kCondBranch_GE,
+    kCondBranch_GT,
+    kCondBranch_LE,
+  };
+
+  enum IntArithmKind {
+    kIntArithm_Add,
+    kIntArithm_Sub,
+    kIntArithm_Mul,
+    kIntArithm_Div,
+    kIntArithm_Rem,
+    kIntArithm_And,
+    kIntArithm_Or,
+    kIntArithm_Xor,
+  };
+
+  enum FPArithmKind {
+    kFPArithm_Add,
+    kFPArithm_Sub,
+    kFPArithm_Mul,
+    kFPArithm_Div,
+    kFPArithm_Rem,
+  };
+
+  enum InvokeArgFmt {
+    kArgReg,
+    kArgRange,
+  };
+
+  llvm::Value* EmitLoadMethodObjectAddr();
+
+  llvm::Value* EmitGetCurrentThread();
+
+  llvm::Value* EmitInvokeIntrinsicNoThrow(IntrinsicHelper::IntrinsicId intr_id);
+  llvm::Value* EmitInvokeIntrinsicNoThrow(IntrinsicHelper::IntrinsicId intr_id,
+                                          llvm::ArrayRef<llvm::Value*> args);
+  llvm::Value* EmitInvokeIntrinsic(unsigned dex_pc,
+                                   IntrinsicHelper::IntrinsicId intr_id);
+  llvm::Value* EmitInvokeIntrinsic(unsigned dex_pc,
+                                   IntrinsicHelper::IntrinsicId intr_id,
+                                   llvm::ArrayRef<llvm::Value*> args);
+  llvm::Value* EmitInvokeIntrinsic2(unsigned dex_pc,
+                                    IntrinsicHelper::IntrinsicId intr_id,
+                                    llvm::Value* arg1,
+                                    llvm::Value* arg2) {
+    llvm::Value* args[] = { arg1, arg2 };
+    return EmitInvokeIntrinsic(dex_pc, intr_id, args);
+  }
+  llvm::Value* EmitInvokeIntrinsic3(unsigned dex_pc,
+                                    IntrinsicHelper::IntrinsicId intr_id,
+                                    llvm::Value* arg1,
+                                    llvm::Value* arg2,
+                                    llvm::Value* arg3) {
+    llvm::Value* args[] = { arg1, arg2, arg3 };
+    return EmitInvokeIntrinsic(dex_pc, intr_id, args);
+  }
+  llvm::Value* EmitInvokeIntrinsic4(unsigned dex_pc,
+                                    IntrinsicHelper::IntrinsicId intr_id,
+                                    llvm::Value* arg1,
+                                    llvm::Value* arg2,
+                                    llvm::Value* arg3,
+                                    llvm::Value* arg4) {
+    llvm::Value* args[] = { arg1, arg2, arg3, arg4 };
+    return EmitInvokeIntrinsic(dex_pc, intr_id, args);
+  }
+  llvm::Value* EmitInvokeIntrinsic5(unsigned dex_pc,
+                                    IntrinsicHelper::IntrinsicId intr_id,
+                                    llvm::Value* arg1,
+                                    llvm::Value* arg2,
+                                    llvm::Value* arg3,
+                                    llvm::Value* arg4,
+                                    llvm::Value* arg5) {
+    llvm::Value* args[] = { arg1, arg2, arg3, arg4, arg5 };
+    return EmitInvokeIntrinsic(dex_pc, intr_id, args);
+  }
+
+  RegCategory GetInferredRegCategory(unsigned dex_pc, unsigned reg_idx);
+
+  llvm::Value* EmitLoadArrayLength(llvm::Value* array);
+
+  llvm::Value* EmitLoadStaticStorage(unsigned dex_pc, unsigned type_idx);
+
+  llvm::Value* EmitConditionResult(llvm::Value* lhs, llvm::Value* rhs,
+                                   CondBranchKind cond);
+
+  llvm::Value* EmitIntArithmResultComputation(unsigned dex_pc,
+                                              llvm::Value* lhs,
+                                              llvm::Value* rhs,
+                                              IntArithmKind arithm,
+                                              JType op_jty);
+
+  llvm::Value* EmitIntDivRemResultComputation(unsigned dex_pc,
+                                              llvm::Value* dividend,
+                                              llvm::Value* divisor,
+                                              IntArithmKind arithm,
+                                              JType op_jty);
+
+#define GEN_INSN_ARGS unsigned dex_pc, const Instruction* insn
+  // NOP, PAYLOAD (unreachable) instructions
+  void EmitInsn_Nop(GEN_INSN_ARGS);
+
+  // MOVE, MOVE_RESULT instructions
+  void EmitInsn_Move(GEN_INSN_ARGS, JType jty);
+  void EmitInsn_MoveResult(GEN_INSN_ARGS, JType jty);
+
+  // MOVE_EXCEPTION, THROW instructions
+  void EmitInsn_MoveException(GEN_INSN_ARGS);
+#if 0
+  void EmitInsn_ThrowException(GEN_INSN_ARGS);
+  void EmitInsn_ThrowVerificationError(GEN_INSN_ARGS);
+
+  // RETURN instructions
+#endif
+  void EmitInsn_ReturnVoid(GEN_INSN_ARGS);
+  void EmitInsn_Return(GEN_INSN_ARGS);
+
+  // CONST, CONST_CLASS, CONST_STRING instructions
+  void EmitInsn_LoadConstant(GEN_INSN_ARGS, JType imm_jty);
+  void EmitInsn_LoadConstantString(GEN_INSN_ARGS);
+#if 0
+  void EmitInsn_LoadConstantClass(GEN_INSN_ARGS);
+
+  // MONITOR_ENTER, MONITOR_EXIT instructions
+  void EmitInsn_MonitorEnter(GEN_INSN_ARGS);
+  void EmitInsn_MonitorExit(GEN_INSN_ARGS);
+
+  // CHECK_CAST, INSTANCE_OF instructions
+  void EmitInsn_CheckCast(GEN_INSN_ARGS);
+  void EmitInsn_InstanceOf(GEN_INSN_ARGS);
+
+  // NEW_INSTANCE instructions
+  void EmitInsn_NewInstance(GEN_INSN_ARGS);
+#endif
+
+  // ARRAY_LEN, NEW_ARRAY, FILLED_NEW_ARRAY, FILL_ARRAY_DATA instructions
+  void EmitInsn_ArrayLength(GEN_INSN_ARGS);
+  void EmitInsn_NewArray(GEN_INSN_ARGS);
+#if 0
+  void EmitInsn_FilledNewArray(GEN_INSN_ARGS, bool is_range);
+  void EmitInsn_FillArrayData(GEN_INSN_ARGS);
+
+#endif
+  // GOTO, IF_TEST, IF_TESTZ instructions
+  void EmitInsn_UnconditionalBranch(GEN_INSN_ARGS);
+  void EmitInsn_BinaryConditionalBranch(GEN_INSN_ARGS, CondBranchKind cond);
+  void EmitInsn_UnaryConditionalBranch(GEN_INSN_ARGS, CondBranchKind cond);
+
+#if 0
+  // PACKED_SWITCH, SPARSE_SWITCH instrutions
+  void EmitInsn_PackedSwitch(GEN_INSN_ARGS);
+  void EmitInsn_SparseSwitch(GEN_INSN_ARGS);
+
+  // CMPX_FLOAT, CMPX_DOUBLE, CMP_LONG instructions
+  void EmitInsn_FPCompare(GEN_INSN_ARGS, JType fp_jty, bool gt_bias);
+  void EmitInsn_LongCompare(GEN_INSN_ARGS);
+
+#endif
+  // AGET, APUT instrutions
+  void EmitInsn_AGet(GEN_INSN_ARGS, JType elem_jty);
+  void EmitInsn_APut(GEN_INSN_ARGS, JType elem_jty);
+
+#if 0
+  // IGET, IPUT instructions
+  void EmitInsn_IGet(GEN_INSN_ARGS, JType field_jty);
+  void EmitInsn_IPut(GEN_INSN_ARGS, JType field_jty);
+#endif
+
+  // SGET, SPUT instructions
+  void EmitInsn_SGet(GEN_INSN_ARGS, JType field_jty);
+  void EmitInsn_SPut(GEN_INSN_ARGS, JType field_jty);
+
+#if 0
+  // INVOKE instructions
+  llvm::Value* EmitFixStub(llvm::Value* callee_method_object_addr,
+                           uint32_t method_idx,
+                           bool is_static);
+  llvm::Value* EmitEnsureResolved(llvm::Value* callee,
+                                  llvm::Value* caller,
+                                  uint32_t dex_method_idx,
+                                  bool is_virtual);
+#endif
+
+  void EmitInsn_Invoke(GEN_INSN_ARGS,
+                       InvokeType invoke_type,
+                       InvokeArgFmt arg_fmt);
+
+#if 0
+  llvm::Value* EmitLoadSDCalleeMethodObjectAddr(uint32_t callee_method_idx);
+
+  llvm::Value* EmitLoadVirtualCalleeMethodObjectAddr(int vtable_idx,
+                                                     llvm::Value* this_addr);
+
+  llvm::Value* EmitCallRuntimeForCalleeMethodObjectAddr(uint32_t callee_method_idx,
+                                                        InvokeType invoke_type,
+                                                        llvm::Value* this_addr,
+                                                        unsigned dex_pc,
+                                                        bool is_fast_path);
+
+  // Unary instructions
+  void EmitInsn_Neg(GEN_INSN_ARGS, JType op_jty);
+  void EmitInsn_Not(GEN_INSN_ARGS, JType op_jty);
+  void EmitInsn_SExt(GEN_INSN_ARGS);
+  void EmitInsn_Trunc(GEN_INSN_ARGS);
+  void EmitInsn_TruncAndSExt(GEN_INSN_ARGS, unsigned N);
+  void EmitInsn_TruncAndZExt(GEN_INSN_ARGS, unsigned N);
+
+  void EmitInsn_FNeg(GEN_INSN_ARGS, JType op_jty);
+  void EmitInsn_IntToFP(GEN_INSN_ARGS, JType src_jty, JType dest_jty);
+  void EmitInsn_FPToInt(GEN_INSN_ARGS, JType src_jty, JType dest_jty,
+                        runtime_support::RuntimeId runtime_func_id);
+  void EmitInsn_FExt(GEN_INSN_ARGS);
+  void EmitInsn_FTrunc(GEN_INSN_ARGS);
+
+#endif
+  // Integer binary arithmetic instructions
+  void EmitInsn_IntArithm(GEN_INSN_ARGS, IntArithmKind arithm,
+                          JType op_jty, bool is_2addr);
+
+  void EmitInsn_IntArithmImmediate(GEN_INSN_ARGS, IntArithmKind arithm);
+
+#if 0
+  void EmitInsn_IntShiftArithm(GEN_INSN_ARGS, IntShiftArithmKind arithm,
+                               JType op_jty, bool is_2addr);
+
+  void EmitInsn_IntShiftArithmImmediate(GEN_INSN_ARGS,
+                                        IntShiftArithmKind arithm);
+
+  void EmitInsn_RSubImmediate(GEN_INSN_ARGS);
+
+#endif
+  // Floating-point binary arithmetic instructions
+  void EmitInsn_FPArithm(GEN_INSN_ARGS, FPArithmKind arithm,
+                         JType op_jty, bool is_2addr);
+#undef GEN_INSN_ARGS
+
+
+  bool EmitInstructions();
+  bool EmitInstruction(unsigned dex_pc, const Instruction* insn);
+
+  DISALLOW_COPY_AND_ASSIGN(DexLang);
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_DEX_LANG_H_
diff --git a/src/greenland/greenland.cc b/src/greenland/greenland.cc
new file mode 100644
index 0000000..bbf990d
--- /dev/null
+++ b/src/greenland/greenland.cc
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "greenland.h"
+
+#include "target_codegen_machine.h"
+#include "target_registry.h"
+
+#include "class_linker.h"
+#include "compiler.h"
+#include "oat_compilation_unit.h"
+#include "stl_util.h"
+#include "utils.h"
+
+#include <vector>
+
+#include <llvm/InitializePasses.h>
+#include <llvm/Module.h>
+#include <llvm/PassRegistry.h>
+#include <llvm/Support/Threading.h>
+
+namespace art {
+namespace greenland {
+
+// Forward declarations
+#define LLVM_TARGET(TargetName) void Initialize##TargetName##CodeGenMachine();
+#include <llvm/Config/Targets.def>
+
+#define LLVM_TARGET(TargetName) \
+    void Initialize##TargetName##InvokeStubCompiler();
+#include <llvm/Config/Targets.def>
+
+} // namespace greeland
+} // namespace art
+
+namespace {
+
+pthread_once_t greenland_initialized = PTHREAD_ONCE_INIT;
+
+void InitializeAllCodeGenMachines() {
+#define LLVM_TARGET(TargetName) \
+  art::greenland::Initialize##TargetName##CodeGenMachine();
+#include <llvm/Config/Targets.def>
+}
+
+void InitializeAllInvokeStubCompilers() {
+#define LLVM_TARGET(TargetName) \
+    art::greenland::Initialize##TargetName##InvokeStubCompiler();
+#include <llvm/Config/Targets.def>
+}
+
+void InitializeGreenland() {
+  // Initialize passes
+  llvm::PassRegistry &registry = *llvm::PassRegistry::getPassRegistry();
+
+  llvm::initializeCore(registry);
+  llvm::initializeScalarOpts(registry);
+
+  // Run vectorization passes when our backend supports vector type
+  //llvm::initializeVectorization(registry);
+
+  // DexLang operates on an llvm::Function and never runs IPO and IPA
+  //llvm::initializeIPO(registry);
+  //llvm::initializeIPA(registry);
+
+  llvm::initializeAnalysis(registry);
+  llvm::initializeTransformUtils(registry);
+  llvm::initializeInstCombine(registry);
+
+  InitializeAllCodeGenMachines();
+  InitializeAllInvokeStubCompilers();
+
+  // Initialize LLVM internal data structure for multithreading
+  llvm::llvm_start_multithreaded();
+
+  return;
+}
+
+} // anonymous namespace
+
+namespace art {
+namespace greenland {
+
+Greenland::Greenland(art::Compiler& compiler)
+    : compiler_(compiler), codegen_machine_(NULL),
+      lock_("greenland_compiler_lock"), cur_dex_lang_ctx_(NULL) {
+  // Initialize Greenland
+  pthread_once(&greenland_initialized, InitializeGreenland);
+
+  codegen_machine_ =
+      TargetCodeGenMachine::Create(compiler_.GetInstructionSet());
+  DCHECK(codegen_machine_ != NULL);
+  return;
+}
+
+Greenland::~Greenland() {
+  cur_dex_lang_ctx_->DecRef();
+  delete codegen_machine_;
+}
+
+CompiledMethod* Greenland::Compile(OatCompilationUnit& cunit) {
+  MutexLock GUARD(lock_);
+
+  // Dex to LLVM IR
+  DexLang::Context& dex_lang_ctx = GetDexLangContext();
+
+  UniquePtr<DexLang> dex_lang(new DexLang(dex_lang_ctx, compiler_, cunit));
+
+  llvm::Function* func = dex_lang->Build();
+
+  if (func == NULL) {
+    LOG(FATAL) << "Failed to run dexlang on "
+               << PrettyMethod(cunit.GetDexMethodIndex(), *cunit.GetDexFile());
+    return NULL;
+  }
+
+  dex_lang_ctx.GetOutputModule().dump();
+
+  UniquePtr<CompiledMethod> result(codegen_machine_->Run(*this, *func, cunit,
+                                                         dex_lang_ctx));
+
+  // dex_lang_ctx was no longer needed
+  dex_lang_ctx.DecRef();
+
+  return result.release();
+}
+
+DexLang::Context& Greenland::GetDexLangContext() {
+  //MutexLock GUARD(lock_);
+
+  ResetDexLangContextIfThresholdReached();
+
+  if (cur_dex_lang_ctx_ == NULL) {
+    cur_dex_lang_ctx_ = new DexLang::Context();
+  }
+  CHECK(cur_dex_lang_ctx_ != NULL);
+
+  return cur_dex_lang_ctx_->IncRef();
+}
+
+void Greenland::ResetDexLangContextIfThresholdReached() {
+  lock_.AssertHeld();
+
+  if (cur_dex_lang_ctx_ == NULL) {
+    return;
+  }
+
+  if (cur_dex_lang_ctx_->IsMemUsageThresholdReached()) {
+    cur_dex_lang_ctx_->DecRef();
+    cur_dex_lang_ctx_ = NULL;
+  }
+  return;
+}
+
+} // namespace greenland
+} // namespace art
+
+inline static art::greenland::Greenland* ContextOf(art::Compiler& compiler) {
+  void *compiler_context = compiler.GetCompilerContext();
+  CHECK(compiler_context != NULL);
+  return reinterpret_cast<art::greenland::Greenland*>(compiler_context);
+}
+
+extern "C" void ArtInitCompilerContext(art::Compiler& compiler) {
+  CHECK(compiler.GetCompilerContext() == NULL);
+  compiler.SetCompilerContext(new art::greenland::Greenland(compiler));
+  return;
+}
+
+extern "C" art::CompiledMethod* ArtCompileMethod(art::Compiler& compiler,
+                                                 const art::DexFile::CodeItem* code_item,
+                                                 uint32_t access_flags, uint32_t method_idx,
+                                                 const art::ClassLoader* class_loader,
+                                                 const art::DexFile& dex_file)
+{
+  art::ClassLinker *class_linker = art::Runtime::Current()->GetClassLinker();
+  art::DexCache *dex_cache = class_linker->FindDexCache(dex_file);
+
+  art::OatCompilationUnit cunit(
+    class_loader, class_linker, dex_file, *dex_cache, code_item,
+    method_idx, access_flags);
+
+  return ContextOf(compiler)->Compile(cunit);
+}
+
+extern "C" art::CompiledInvokeStub* ArtCreateInvokeStub(art::Compiler& compiler,
+                                                        bool is_static,
+                                                        const char* shorty,
+                                                        uint32_t shorty_len) {
+  art::greenland::TargetRegistry::CreateInvokeStubFn compiler_fn =
+      art::greenland::TargetRegistry::GetInvokeStubCompiler(compiler.GetInstructionSet());
+  CHECK(compiler_fn != NULL);
+  return (*compiler_fn)(compiler, is_static, shorty, shorty_len);
+}
diff --git a/src/greenland/greenland.h b/src/greenland/greenland.h
new file mode 100644
index 0000000..4407c92
--- /dev/null
+++ b/src/greenland/greenland.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_GREENLAND_H_
+#define ART_SRC_GREENLAND_GREENLAND_H_
+
+#include "dex_lang.h"
+
+#include "macros.h"
+#include "object.h"
+
+namespace art {
+  class CompiledMethod;
+  class Compiler;
+  class OatCompilationUnit;
+}
+
+namespace art {
+namespace greenland {
+
+class TargetCodeGenMachine;
+
+class Greenland {
+ public:
+  Greenland(art::Compiler& compiler);
+  ~Greenland();
+
+  CompiledMethod* Compile(OatCompilationUnit& cunit);
+
+  const Compiler& GetCompiler() const {
+    return compiler_;
+  }
+  Compiler& GetCompiler() {
+    return compiler_;
+  }
+
+ private:
+  Compiler& compiler_;
+
+  TargetCodeGenMachine* codegen_machine_;
+
+  Mutex lock_;
+
+  // NOTE: Ensure that the lock_ is held before altering cur_dex_lang_ctx_
+  DexLang::Context *cur_dex_lang_ctx_;
+
+  DexLang::Context& GetDexLangContext();
+  void ResetDexLangContextIfThresholdReached();
+
+  DISALLOW_COPY_AND_ASSIGN(Greenland);
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_GREENLAND_H_
diff --git a/src/greenland/inferred_reg_category_map.cc b/src/greenland/inferred_reg_category_map.cc
new file mode 100644
index 0000000..4f7f4ff
--- /dev/null
+++ b/src/greenland/inferred_reg_category_map.cc
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "inferred_reg_category_map.h"
+
+#include "backend_types.h"
+#include "stl_util.h"
+
+#include <stdint.h>
+#include <vector>
+
+namespace art {
+namespace greenland {
+
+InferredRegCategoryMap::InferredRegCategoryMap(uint32_t insns_size,
+                                               uint8_t regs_size)
+: registers_size_(regs_size), lines_(insns_size, NULL), can_be_object_(regs_size) {
+}
+
+InferredRegCategoryMap::~InferredRegCategoryMap() {
+  STLDeleteElements(&lines_);
+}
+
+RegCategory InferredRegCategoryMap::GetRegCategory(uint32_t dex_pc,
+                                                   uint16_t reg_idx) const {
+  if (lines_[dex_pc] == NULL) {
+    return kRegUnknown;
+  }
+  return lines_[dex_pc]->GetRegCategory(reg_idx);
+}
+
+void InferredRegCategoryMap::SetRegCategory(uint32_t dex_pc,
+                                            uint16_t reg_idx,
+                                            RegCategory cat) {
+  if (cat != kRegUnknown) {
+    if (lines_[dex_pc] == NULL) {
+      lines_[dex_pc] = new RegCategoryLine();
+    }
+
+    (*lines_[dex_pc]).SetRegCategory(reg_idx, cat);
+  }
+}
+
+bool InferredRegCategoryMap::IsRegCanBeObject(uint16_t reg_idx) const {
+  return can_be_object_[reg_idx];
+}
+
+void InferredRegCategoryMap::SetRegCanBeObject(uint16_t reg_idx) {
+  can_be_object_[reg_idx] = true;
+}
+
+bool InferredRegCategoryMap::
+operator==(InferredRegCategoryMap const& rhs) const {
+
+  if (registers_size_ != rhs.registers_size_) {
+    return false;
+  }
+
+  if (lines_.size() != rhs.lines_.size()) {
+    return false;
+  }
+
+  for (size_t i = 0; i < lines_.size(); ++i) {
+    if (lines_[i] == NULL && rhs.lines_[i] == NULL) {
+      continue;
+    }
+
+    if ((lines_[i] == NULL && rhs.lines_[i] != NULL) ||
+        (lines_[i] != NULL && rhs.lines_[i] == NULL)) {
+      return false;
+    }
+
+    if (*lines_[i] != *rhs.lines_[i]) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool InferredRegCategoryMap::
+operator!=(InferredRegCategoryMap const& rhs) const {
+
+  return !(*this == rhs);
+}
+
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/inferred_reg_category_map.h b/src/greenland/inferred_reg_category_map.h
new file mode 100644
index 0000000..57e0c30
--- /dev/null
+++ b/src/greenland/inferred_reg_category_map.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_INFERRED_REG_CATEGORY_MAP_H_
+#define ART_SRC_GREENLAND_INFERRED_REG_CATEGORY_MAP_H_
+
+#include "backend_types.h"
+
+#include <stdint.h>
+#include <vector>
+
+#include "safe_map.h"
+
+namespace art {
+namespace greenland {
+
+class InferredRegCategoryMap {
+ private:
+  class RegCategoryLine {
+   private:
+    typedef SafeMap<uint16_t, uint8_t> Table;
+    Table reg_category_line_;
+
+   public:
+    RegCategory GetRegCategory(uint16_t reg_idx) const {
+      // TODO: C++0x auto
+      Table::const_iterator result = reg_category_line_.find(reg_idx);
+      if (result == reg_category_line_.end()) {
+        return kRegUnknown;
+      }
+      return static_cast<RegCategory>(result->second);
+    }
+
+    void SetRegCategory(uint16_t reg_idx, RegCategory cat) {
+      if (cat != kRegUnknown) {
+        reg_category_line_.Put(reg_idx, cat);
+      }
+    }
+
+    bool operator==(RegCategoryLine const& rhs) const {
+      return reg_category_line_ == rhs.reg_category_line_;
+    }
+    bool operator!=(RegCategoryLine const& rhs) const {
+      return reg_category_line_ != rhs.reg_category_line_;
+    }
+  };
+
+ public:
+  InferredRegCategoryMap(uint32_t insns_size_in_code_units, uint8_t regs_size);
+
+  ~InferredRegCategoryMap();
+
+  RegCategory GetRegCategory(uint32_t dex_pc, uint16_t reg_idx) const;
+  void SetRegCategory(uint32_t dex_pc, uint16_t reg_idx, RegCategory cat);
+
+  bool IsRegCanBeObject(uint16_t reg_idx) const;
+  void SetRegCanBeObject(uint16_t reg_idx);
+
+  bool operator==(InferredRegCategoryMap const& rhs) const;
+  bool operator!=(InferredRegCategoryMap const& rhs) const;
+
+ private:
+  uint16_t registers_size_;
+
+  std::vector<RegCategoryLine*> lines_;
+
+  std::vector<bool> can_be_object_;
+
+  DISALLOW_COPY_AND_ASSIGN(InferredRegCategoryMap);
+};
+
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_INFERRED_REG_CATEGORY_MAP_H_
diff --git a/src/greenland/intrinsic_func_list.def b/src/greenland/intrinsic_func_list.def
new file mode 100644
index 0000000..48c1247
--- /dev/null
+++ b/src/greenland/intrinsic_func_list.def
@@ -0,0 +1,616 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// DEF_INTRINSICS_FUNC(ID, NAME, ATTR, RET_TYPE,
+//                     ARG1_TYPE, ARG2_TYPE, ARG3_TYPE, ARG4_TYPE, ARG5_TYPE)
+#ifndef DEF_INTRINSICS_FUNC
+#  error "missing DEF_INTRINSICS_FUNC definition!"
+#endif
+
+#define _EVAL_DEF_INTRINSICS_FUNC(ID, NAME, ATTR, RET_TYPE, ...) \
+    DEF_INTRINSICS_FUNC(ID, NAME, ATTR, RET_TYPE, __VA_ARGS__)
+
+#define _EXPAND_ARG0()                         kNone, kNone, kNone, kNone, kNone
+#define _EXPAND_ARG1(ARG1)                      ARG1, kNone, kNone, kNone, kNone
+#define _EXPAND_ARG2(ARG1, ARG2)                ARG1,  ARG2, kNone, kNone, kNone
+#define _EXPAND_ARG3(ARG1, ARG2, ARG3)          ARG1,  ARG2,  ARG3, kNone, kNone
+#define _EXPAND_ARG4(ARG1, ARG2, ARG3, ARG4)    ARG1,  ARG2,  ARG3,  ARG4, kNone
+#define _EXPAND_ARG5(ARG1, ARG2, ARG3, ARG4, ARG5) \
+                                                ARG1,  ARG2,  ARG3,  ARG4,  ARG5
+
+#define _JTYPE(TYPE, SPACE) _JTYPE_OF_ ## TYPE ## _UNDER_ ## SPACE
+
+// Note: These should be consistent with the type return from
+// IRBuilder::GetJType([type], kArray).
+#define _JTYPE_OF_kInt1Ty_UNDER_kArray        kInt8Ty
+#define _JTYPE_OF_kInt8Ty_UNDER_kArray        kInt8Ty
+#define _JTYPE_OF_kInt16Ty_UNDER_kArray       kInt16Ty
+#define _JTYPE_OF_kInt32Ty_UNDER_kArray       kInt32Ty
+#define _JTYPE_OF_kInt64Ty_UNDER_kArray       kInt64Ty
+#define _JTYPE_OF_kJavaObjectTy_UNDER_kArray  kJavaObjectTy
+
+// Note: These should be consistent with the type return from
+// IRBuilder::GetJType([type], kField).
+#define _JTYPE_OF_kInt1Ty_UNDER_kField        kInt32Ty
+#define _JTYPE_OF_kInt8Ty_UNDER_kField        kInt32Ty
+#define _JTYPE_OF_kInt16Ty_UNDER_kField       kInt32Ty
+#define _JTYPE_OF_kInt32Ty_UNDER_kField       kInt32Ty
+#define _JTYPE_OF_kInt64Ty_UNDER_kField       kInt64Ty
+#define _JTYPE_OF_kJavaObjectTy_UNDER_kField  kJavaObjectTy
+
+//----------------------------------------------------------------------------
+// Thread
+//----------------------------------------------------------------------------
+
+// Thread* dex_lang_get_current_thread()
+_EVAL_DEF_INTRINSICS_FUNC(GetCurrentThread,
+                          dex_lang_get_current_thread,
+                          kAttrReadOnly | kAttrNoThrow,
+                           kJavaThreadTy,
+                          _EXPAND_ARG0())
+
+//----------------------------------------------------------------------------
+// Exception
+//----------------------------------------------------------------------------
+
+// JavaObject* dex_lang_get_current_exception()
+_EVAL_DEF_INTRINSICS_FUNC(GetException,
+                          dex_lang_get_current_exception,
+                          kAttrReadOnly | kAttrNoThrow,
+                           kJavaObjectTy,
+                          _EXPAND_ARG0())
+
+// bool dex_lang_is_exception_pending()
+_EVAL_DEF_INTRINSICS_FUNC(IsExceptionPending,
+                          dex_lang_is_exception_pending,
+                          kAttrReadOnly | kAttrNoThrow,
+                          kInt1Ty,
+                          _EXPAND_ARG0())
+
+// int dex_lang_find_catch_block(Method* method, int try_item_offset)
+_EVAL_DEF_INTRINSICS_FUNC(FindCatchBlock,
+                          dex_lang_find_catch_block,
+                          kAttrReadOnly | kAttrNoThrow,
+                          kInt32Ty,
+                          _EXPAND_ARG2(kJavaMethodTy, kInt32ConstantTy))
+
+// void dex_lang_throw_div_zero()
+_EVAL_DEF_INTRINSICS_FUNC(ThrowDivZeroException,
+                          dex_lang_throw_div_zero,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG0())
+
+// void dex_lang_throw_null_pointer_exception(uint32_t dex_pc)
+_EVAL_DEF_INTRINSICS_FUNC(ThrowNullPointerException,
+                          dex_lang_throw_null_pointer_exception,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG1(kInt32ConstantTy))
+
+// void dex_lang_throw_array_bounds(int index, int array_len)
+_EVAL_DEF_INTRINSICS_FUNC(ThrowIndexOutOfBounds,
+                          dex_lang_throw_array_bounds,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG2(kInt32Ty, kInt32Ty))
+
+//----------------------------------------------------------------------------
+// ConstString
+//----------------------------------------------------------------------------
+
+// JavaObject* dex_lang_const_string(uint32_t string_idx)
+_EVAL_DEF_INTRINSICS_FUNC(ConstString,
+                          dex_lang_const_string,
+                          kAttrReadOnly | kAttrNoThrow,
+                          kJavaObjectTy,
+                          _EXPAND_ARG1(kInt32ConstantTy))
+
+// JavaObject* dex_lang_const_string(uint32_t string_idx)
+_EVAL_DEF_INTRINSICS_FUNC(ConstStringFast,
+                          dex_lang_const_string.fast,
+                          kAttrReadOnly | kAttrNoThrow,
+                          kJavaObjectTy,
+                          _EXPAND_ARG1(kInt32ConstantTy))
+
+//----------------------------------------------------------------------------
+// Array
+//----------------------------------------------------------------------------
+
+// uint32_t dex_lang_array_length(JavaObject* array)
+_EVAL_DEF_INTRINSICS_FUNC(ArrayLength,
+                          dex_lang_array_length,
+                          kAttrReadOnly | kAttrNoThrow,
+                          kInt32Ty,
+                          _EXPAND_ARG1(kJavaObjectTy))
+
+// JavaObject* dex_lang_new_array(uint32_t type_idx, uint32_t array_size)
+_EVAL_DEF_INTRINSICS_FUNC(NewArray,
+                          dex_lang_new_array,
+                          kAttrNone,
+                          kJavaObjectTy,
+                          _EXPAND_ARG2(kInt32ConstantTy, kInt32Ty))
+
+// dex_lang_aget_* and dex_lang_aput_* never generate exception since the
+// necessary checking on arguments (e.g., array and index) has already done
+// before invocation of these intrinsics.
+//
+// [type] void dex_lang_aget_[type](JavaObject* array, uint32_t index)
+_EVAL_DEF_INTRINSICS_FUNC(ArrayGet,
+                          dex_lang_aget,
+                          kAttrReadOnly | kAttrNoThrow,
+                          _JTYPE(kInt32Ty, kArray),
+                          _EXPAND_ARG2(kJavaObjectTy, kInt32Ty))
+
+_EVAL_DEF_INTRINSICS_FUNC(ArrayGetWide,
+                          dex_lang_aget_wide,
+                          kAttrReadOnly | kAttrNoThrow,
+                          _JTYPE(kInt64Ty, kArray),
+                          _EXPAND_ARG2(kJavaObjectTy, kInt32Ty))
+
+_EVAL_DEF_INTRINSICS_FUNC(ArrayGetObject,
+                          dex_lang_aget_object,
+                          kAttrReadOnly | kAttrNoThrow,
+                          _JTYPE(kJavaObjectTy, kArray),
+                          _EXPAND_ARG2(kJavaObjectTy, kInt32Ty))
+
+_EVAL_DEF_INTRINSICS_FUNC(ArrayGetBoolean,
+                          dex_lang_aget_boolean,
+                          kAttrReadOnly | kAttrNoThrow,
+                          _JTYPE(kInt1Ty, kArray),
+                          _EXPAND_ARG2(kJavaObjectTy, kInt32Ty))
+
+_EVAL_DEF_INTRINSICS_FUNC(ArrayGetByte,
+                          dex_lang_aget_byte,
+                          kAttrReadOnly | kAttrNoThrow,
+                          _JTYPE(kInt8Ty, kArray),
+                          _EXPAND_ARG2(kJavaObjectTy, kInt32Ty))
+
+_EVAL_DEF_INTRINSICS_FUNC(ArrayGetChar,
+                          dex_lang_aget_char,
+                          kAttrReadOnly | kAttrNoThrow,
+                          _JTYPE(kInt16Ty, kArray),
+                          _EXPAND_ARG2(kJavaObjectTy, kInt32Ty))
+
+_EVAL_DEF_INTRINSICS_FUNC(ArrayGetShort,
+                          dex_lang_aget_short,
+                          kAttrReadOnly | kAttrNoThrow,
+                          _JTYPE(kInt16Ty, kArray),
+                          _EXPAND_ARG2(kJavaObjectTy, kInt32Ty))
+
+// void dex_lang_aput_[type]([type] value, JavaObject* array, uint32_t index)
+_EVAL_DEF_INTRINSICS_FUNC(ArrayPut,
+                          dex_lang_aput,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG3(_JTYPE(kInt32Ty, kArray), kJavaObjectTy, kInt32Ty))
+
+_EVAL_DEF_INTRINSICS_FUNC(ArrayPutWide,
+                          dex_lang_aput_wide,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG3(_JTYPE(kInt64Ty, kArray), kJavaObjectTy, kInt32Ty))
+
+_EVAL_DEF_INTRINSICS_FUNC(ArrayPutObject,
+                          dex_lang_aput_object,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG3(_JTYPE(kJavaObjectTy, kArray), kJavaObjectTy, kInt32Ty))
+
+_EVAL_DEF_INTRINSICS_FUNC(ArrayPutBoolean,
+                          dex_lang_aput_boolean,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG3(_JTYPE(kInt1Ty, kArray), kJavaObjectTy, kInt32Ty))
+
+_EVAL_DEF_INTRINSICS_FUNC(ArrayPutByte,
+                          dex_lang_aput_byte,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG3(_JTYPE(kInt8Ty, kArray), kJavaObjectTy, kInt32Ty))
+
+_EVAL_DEF_INTRINSICS_FUNC(ArrayPutChar,
+                          dex_lang_aput_char,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG3(_JTYPE(kInt16Ty, kArray), kJavaObjectTy, kInt32Ty))
+
+_EVAL_DEF_INTRINSICS_FUNC(ArrayPutShort,
+                          dex_lang_aput_short,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG3(_JTYPE(kInt16Ty, kArray), kJavaObjectTy, kInt32Ty))
+
+// void dex_lang_check_put_array_element(JavaObject* value, JavaObject* array)
+_EVAL_DEF_INTRINSICS_FUNC(CheckPutArrayElement,
+                          dex_lang_check_put_array_element,
+                          kAttrReadOnly | kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG2(kJavaObjectTy, kJavaObjectTy))
+
+//----------------------------------------------------------------------------
+// Static Field
+//----------------------------------------------------------------------------
+
+// [type] dex_lang_sget_[type](uint32_t field_idx, Method* referrer)
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGet,
+                          dex_lang_sget,
+                          kAttrReadOnly,
+                          _JTYPE(kInt32Ty, kField),
+                          _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetWide,
+                          dex_lang_sget_wide,
+                          kAttrReadOnly,
+                          _JTYPE(kInt64Ty, kField),
+                          _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetObject,
+                          dex_lang_sget_object,
+                          kAttrReadOnly,
+                          _JTYPE(kJavaObjectTy, kField),
+                          _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetBoolean,
+                          dex_lang_sget_boolean,
+                          kAttrReadOnly,
+                          _JTYPE(kInt1Ty, kField),
+                          _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetByte,
+                          dex_lang_sget_byte,
+                          kAttrReadOnly,
+                          _JTYPE(kInt8Ty, kField),
+                          _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetChar,
+                          dex_lang_sget_char,
+                          kAttrReadOnly,
+                          _JTYPE(kInt16Ty, kField),
+                          _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetShort,
+                          dex_lang_sget_short,
+                          kAttrReadOnly,
+                          _JTYPE(kInt16Ty, kField),
+                          _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
+
+// [type] dex_lang_sget_[type].fast(JavaObject* ssb,
+//                                  int field_offset,
+//                                  bool is_volatile)
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetFast,
+                          dex_lang_sget.fast,
+                          kAttrReadOnly | kAttrNoThrow,
+                          _JTYPE(kInt32Ty, kField),
+                          _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetWideFast,
+                          dex_lang_sget_wide.fast,
+                          kAttrReadOnly | kAttrNoThrow,
+                          _JTYPE(kInt64Ty, kField),
+                          _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetObjectFast,
+                          dex_lang_sget_object.fast,
+                          kAttrReadOnly | kAttrNoThrow,
+                          _JTYPE(kJavaObjectTy, kField),
+                          _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetBooleanFast,
+                          dex_lang_sget_boolean.fast,
+                          kAttrReadOnly | kAttrNoThrow,
+                          _JTYPE(kInt1Ty, kField),
+                          _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetByteFast,
+                          dex_lang_sget_byte.fast,
+                          kAttrReadOnly | kAttrNoThrow,
+                          _JTYPE(kInt8Ty, kField),
+                          _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetCharFast,
+                          dex_lang_sget_char.fast,
+                          kAttrReadOnly | kAttrNoThrow,
+                          _JTYPE(kInt16Ty, kField),
+                          _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetShortFast,
+                          dex_lang_sget_short.fast,
+                          kAttrReadOnly | kAttrNoThrow,
+                          _JTYPE(kInt16Ty, kField),
+                          _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy))
+
+// void dex_lang_sput_[type](uint32_t field_idx,
+//                           Method* referrer,
+//                           [type] new_value)
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPut,
+                          dex_lang_sput,
+                          kAttrNone,
+                          kVoidTy,
+                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kInt32Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutWide,
+                          dex_lang_sput_wide,
+                          kAttrNone,
+                          kVoidTy,
+                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kInt64Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutObject,
+                          dex_lang_sput_object,
+                          kAttrNone,
+                          kVoidTy,
+                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kJavaObjectTy, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutBoolean,
+                          dex_lang_sput_boolean,
+                          kAttrNone,
+                          kVoidTy,
+                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kInt1Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutByte,
+                          dex_lang_sput_byte,
+                          kAttrNone,
+                          kVoidTy,
+                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kInt8Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutChar,
+                          dex_lang_sput_char,
+                          kAttrNone,
+                          kVoidTy,
+                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kInt16Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutShort,
+                          dex_lang_sput_short,
+                          kAttrNone,
+                          kVoidTy,
+                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kInt16Ty, kField)))
+
+// void dex_lang_sput_[type].fast(JavaObject* ssb,
+//                                int field_offset,
+//                                bool is_volatile,
+//                                [type] new_value)
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutFast,
+                          dex_lang_sput.fast,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kInt32Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutWideFast,
+                          dex_lang_sput_wide.fast,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kInt64Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutObjectFast,
+                          dex_lang_sput_object.fast,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kJavaObjectTy, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutBooleanFast,
+                          dex_lang_sput_boolean.fast,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kInt1Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutByteFast,
+                          dex_lang_sput_byte.fast,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kInt8Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutCharFast,
+                          dex_lang_sput_char.fast,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kInt16Ty, kField)))
+
+_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutShortFast,
+                          dex_lang_sput_short.fast,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kInt16Ty, kField)))
+
+// JavaObject* dex_lang_load_declaring_class_ssb(Method* method)
+// Load the static storage base of the class that given method resides
+_EVAL_DEF_INTRINSICS_FUNC(LoadDeclaringClassSSB,
+                          dex_lang_load_declaring_class_ssb,
+                          kAttrReadOnly | kAttrNoThrow,
+                          kJavaObjectTy,
+                          _EXPAND_ARG1(kJavaMethodTy))
+
+// JavaObject* dex_lang_load_class_ssb_from_dex_cache(uint32_t type_idx)
+_EVAL_DEF_INTRINSICS_FUNC(LoadClassSSBFromDexCache,
+                          dex_lang_load_class_ssb_from_dex_cache,
+                          kAttrReadOnly | kAttrNoThrow,
+                          kJavaObjectTy,
+                          _EXPAND_ARG1(kInt32ConstantTy))
+
+// JavaObject* dex_lang_init_and_load_class_ssb(uint32_t type_idx,
+//                                              Method* referrer,
+//                                              Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(InitializeAndLoadClassSSB,
+                          dex_lang_init_and_load_class_ssb,
+                          kAttrNone,
+                          kJavaObjectTy,
+                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy))
+
+//----------------------------------------------------------------------------
+// Invoke
+//----------------------------------------------------------------------------
+
+// Method* dex_lang_get_callee_method_obj_addr(uint32_t method_idx,
+//                                             JavaObject* this,
+//                                             Method* referrer,
+//                                             Thread* thread,
+//                                             InvokeType type)
+_EVAL_DEF_INTRINSICS_FUNC(GetCalleeMethodObjAddr,
+                          dex_lang_get_callee_method_obj_addr,
+                          kAttrReadOnly,
+                          kJavaMethodTy,
+                          _EXPAND_ARG5(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy, kInt32ConstantTy))
+
+// Method* dex_lang_get_sd_callee_method_obj_addr(uint32_t method_idx)
+_EVAL_DEF_INTRINSICS_FUNC(GetSDCalleeMethodObjAddrFast,
+                          dex_lang_get_sd_callee_method_obj_addr_fast,
+                          kAttrReadOnly,
+                          kJavaMethodTy,
+                          _EXPAND_ARG1(kInt32ConstantTy))
+
+// Method* dex_lang_get_virtual_callee_method_obj_addr(uint32_t vtable_idx,
+//                                                     JavaObject* this)
+_EVAL_DEF_INTRINSICS_FUNC(GetVirtualCalleeMethodObjAddrFast,
+                          dex_lang_get_virtual_callee_method_obj_addr_fast,
+                          kAttrReadOnly | kAttrNoThrow,
+                          kJavaMethodTy,
+                          _EXPAND_ARG2(kInt32ConstantTy, kJavaObjectTy))
+
+// Method* dex_lang_get_interface_callee_method_obj_addr(uint32_t method_idx,
+//                                                       JavaObject* this,
+//                                                       Method* referrer,
+//                                                       Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(GetInterfaceCalleeMethodObjAddrFast,
+                          dex_lang_get_interface_callee_method_obj_addr_fast,
+                          kAttrReadOnly,
+                          kJavaMethodTy,
+                          _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy))
+
+// [type] dex_lang_invoke.[type](Method* callee, ...)
+// INVOKE method returns void
+_EVAL_DEF_INTRINSICS_FUNC(InvokeRetVoid,
+                          dex_lang_invoke.void,
+                          kAttrNone,
+                          kVoidTy,
+                          _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
+
+// INVOKE method returns the value of type in Dalvik register category 1
+_EVAL_DEF_INTRINSICS_FUNC(InvokeRetCat1,
+                          dex_lang_invoke.i32,
+                          kAttrNone,
+                          kInt32Ty,
+                          _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
+
+// INVOKE method returns the value of type in Dalvik register category 2
+_EVAL_DEF_INTRINSICS_FUNC(InvokeRetCat2,
+                          dex_lang_invoke.i64,
+                          kAttrNone,
+                          kInt64Ty,
+                          _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
+
+// INVOKE method returns the value of type in Dalvik register category "object"
+_EVAL_DEF_INTRINSICS_FUNC(InvokeRetObject,
+                          dex_lang_invoke.object,
+                          kAttrNone,
+                          kJavaObjectTy,
+                          _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
+
+//----------------------------------------------------------------------------
+// Math
+//----------------------------------------------------------------------------
+
+// int dex_lang_{div,rem}_int(int a, int b)
+_EVAL_DEF_INTRINSICS_FUNC(DivInt,
+                          dex_lang_div_int,
+                          kAttrReadOnly | kAttrNoThrow,
+                          kInt32Ty,
+                          _EXPAND_ARG2(kInt32Ty, kInt32Ty))
+
+_EVAL_DEF_INTRINSICS_FUNC(RemInt,
+                          dex_lang_rem_int,
+                          kAttrReadOnly | kAttrNoThrow,
+                          kInt32Ty,
+                          _EXPAND_ARG2(kInt32Ty, kInt32Ty))
+
+// long dex_lang_{div,rem}_long(long a, long b)
+_EVAL_DEF_INTRINSICS_FUNC(DivLong,
+                          dex_lang_div_long,
+                          kAttrReadOnly | kAttrNoThrow,
+                          kInt64Ty,
+                          _EXPAND_ARG2(kInt64Ty, kInt64Ty))
+
+_EVAL_DEF_INTRINSICS_FUNC(RemLong,
+                          dex_lang_rem_long,
+                          kAttrReadOnly | kAttrNoThrow,
+                          kInt64Ty,
+                          _EXPAND_ARG2(kInt64Ty, kInt64Ty))
+
+//----------------------------------------------------------------------------
+// Suspend Test
+//----------------------------------------------------------------------------
+
+// void dex_lang_test_suspend(Thread* thread)
+_EVAL_DEF_INTRINSICS_FUNC(TestSuspend,
+                          dex_lang_test_suspend,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG1(kJavaThreadTy))
+
+//----------------------------------------------------------------------------
+// Shadow Frame
+//----------------------------------------------------------------------------
+
+// void dex_lang_alloca_shadow_frame(int num_entry)
+_EVAL_DEF_INTRINSICS_FUNC(AllocaShadowFrame,
+                          dex_lang_alloca_shadow_frame,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG1(kInt32ConstantTy))
+
+// void dex_lang_set_shadow_frame_entry(JavaObject* obj, int entry_idx)
+_EVAL_DEF_INTRINSICS_FUNC(SetShadowFrameEntry,
+                          dex_lang_set_shadow_frame_entry,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG2(kJavaObjectTy, kInt32ConstantTy))
+
+// void dex_lang_pop_shadow_frame()
+_EVAL_DEF_INTRINSICS_FUNC(PopShadowFrame,
+                          dex_lang_pop_shadow_frame,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG0())
+
+// void dex_lang_update_dex_pc(uint32_t dex_pc)
+_EVAL_DEF_INTRINSICS_FUNC(UpdateDexPC,
+                          dex_lang_update_dex_pc,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG1(kInt32ConstantTy))
+
+
+// Clean up all internal used macros
+#undef _EXPAND_ARG0
+#undef _EXPAND_ARG1
+#undef _EXPAND_ARG2
+#undef _EXPAND_ARG3
+#undef _EXPAND_ARG4
+#undef _EXPAND_ARG5
+
+#undef _JTYPE_OF_kInt1Ty_UNDER_kArray
+#undef _JTYPE_OF_kInt8Ty_UNDER_kArray
+#undef _JTYPE_OF_kInt16Ty_UNDER_kArray
+#undef _JTYPE_OF_kInt32Ty_UNDER_kArray
+#undef _JTYPE_OF_kInt64Ty_UNDER_kArray
+#undef _JTYPE_OF_kJavaObjectTy_UNDER_kArray
+
+#undef _JTYPE_OF_kInt1Ty_UNDER_kField
+#undef _JTYPE_OF_kInt8Ty_UNDER_kField
+#undef _JTYPE_OF_kInt16Ty_UNDER_kField
+#undef _JTYPE_OF_kInt32Ty_UNDER_kField
+#undef _JTYPE_OF_kInt64Ty_UNDER_kField
+#undef _JTYPE_OF_kJavaObjectTy_UNDER_kField
+
+#undef DEF_INTRINSICS_FUNC
diff --git a/src/greenland/intrinsic_helper.cc b/src/greenland/intrinsic_helper.cc
new file mode 100644
index 0000000..07836bb
--- /dev/null
+++ b/src/greenland/intrinsic_helper.cc
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "intrinsic_helper.h"
+
+#include "ir_builder.h"
+
+#include <llvm/DerivedTypes.h>
+#include <llvm/Function.h>
+#include <llvm/Intrinsics.h>
+#include <llvm/Module.h>
+#include <llvm/Support/IRBuilder.h>
+
+using namespace art;
+using namespace greenland;
+
+namespace {
+
+inline llvm::Type*
+GetLLVMTypeOfIntrinsicValType(IRBuilder& irb,
+                              IntrinsicHelper::IntrinsicValType type) {
+  switch (type) {
+    case IntrinsicHelper::kVoidTy: {
+      return irb.getVoidTy();
+    }
+    case IntrinsicHelper::kJavaObjectTy: {
+      return irb.GetJObjectTy();
+    }
+    case IntrinsicHelper::kJavaMethodTy: {
+      return irb.GetJMethodTy();
+    }
+    case IntrinsicHelper::kJavaThreadTy: {
+      return irb.GetJThreadTy();
+    }
+    case IntrinsicHelper::kInt1Ty:
+    case IntrinsicHelper::kInt1ConstantTy: {
+      return irb.getInt1Ty();
+    }
+    case IntrinsicHelper::kInt8Ty:
+    case IntrinsicHelper::kInt8ConstantTy: {
+      return irb.getInt8Ty();
+    }
+    case IntrinsicHelper::kInt16Ty:
+    case IntrinsicHelper::kInt16ConstantTy: {
+      return irb.getInt16Ty();
+    }
+    case IntrinsicHelper::kInt32Ty:
+    case IntrinsicHelper::kInt32ConstantTy: {
+      return irb.getInt32Ty();
+    }
+    case IntrinsicHelper::kInt64Ty:
+    case IntrinsicHelper::kInt64ConstantTy: {
+      return irb.getInt64Ty();
+    }
+    case IntrinsicHelper::kNone:
+    case IntrinsicHelper::kVarArgTy:
+    default: {
+      LOG(FATAL) << "Invalid intrinsic type " << type << "to get LLVM type!";
+      return NULL;
+    }
+  }
+  // unreachable
+}
+
+} // anonymous namespace
+
+namespace art {
+namespace greenland {
+
+const IntrinsicHelper::IntrinsicInfo IntrinsicHelper::Info[MaxIntrinsicId] = {
+#define DEF_INTRINSICS_FUNC(_, NAME, ATTR, RET_TYPE, ARG1_TYPE, ARG2_TYPE, \
+                                                     ARG3_TYPE, ARG4_TYPE, \
+                                                     ARG5_TYPE) \
+  { #NAME, ATTR, RET_TYPE, { ARG1_TYPE, ARG2_TYPE, \
+                             ARG3_TYPE, ARG4_TYPE, \
+                             ARG5_TYPE} },
+#include "intrinsic_func_list.def"
+};
+
+IntrinsicHelper::IntrinsicHelper(llvm::LLVMContext& context,
+                                 llvm::Module& module) {
+  IRBuilder irb(context, module, *this);
+
+  ::memset(intrinsic_funcs_, 0, sizeof(intrinsic_funcs_));
+
+  // This loop does the following things:
+  // 1. Introduce the intrinsic function into the module
+  // 2. Add "nocapture" and "noalias" attribute to the arguments in all
+  //    intrinsics functions.
+  // 3. Initialize intrinsic_funcs_map_.
+  for (unsigned i = 0; i < MaxIntrinsicId; i++) {
+    IntrinsicId id = static_cast<IntrinsicId>(i);
+    const IntrinsicInfo& info = Info[i];
+
+    // Parse and construct the argument type from IntrinsicInfo
+    llvm::Type* arg_type[kIntrinsicMaxArgc];
+    unsigned num_args = 0;
+    bool is_var_arg = false;
+    for (unsigned arg_iter = 0; arg_iter < kIntrinsicMaxArgc; arg_iter++) {
+      IntrinsicValType type = info.arg_type_[arg_iter];
+
+      if (type == kNone) {
+        break;
+      } else if (type == kVarArgTy) {
+        // Variable argument type must be the last argument
+        is_var_arg = true;
+        break;
+      }
+
+      arg_type[num_args++] = GetLLVMTypeOfIntrinsicValType(irb, type);
+    }
+
+    // Construct the function type
+    llvm::Type* ret_type =
+        GetLLVMTypeOfIntrinsicValType(irb, info.ret_val_type_);
+
+    llvm::FunctionType* type =
+        llvm::FunctionType::get(ret_type,
+                                llvm::ArrayRef<llvm::Type*>(arg_type, num_args),
+                                is_var_arg);
+
+    // Declare the function
+    llvm::Function *fn = llvm::Function::Create(type,
+                                                llvm::Function::ExternalLinkage,
+                                                info.name_, &module);
+
+    fn->setOnlyReadsMemory(info.attr_ & kAttrReadOnly);
+    // None of the intrinsics throws exception
+    fn->setDoesNotThrow(true);
+
+    intrinsic_funcs_[id] = fn;
+
+    DCHECK_NE(fn, static_cast<llvm::Function*>(NULL)) << "Intrinsic `"
+        << GetName(id) << "' was not defined!";
+
+    // Add "noalias" and "nocapture" attribute to all arguments of pointer type
+    for (llvm::Function::arg_iterator arg_iter = fn->arg_begin(),
+            arg_end = fn->arg_end(); arg_iter != arg_end; arg_iter++) {
+      if (arg_iter->getType()->isPointerTy()) {
+        arg_iter->addAttr(llvm::Attribute::NoCapture);
+        arg_iter->addAttr(llvm::Attribute::NoAlias);
+      }
+    }
+
+    // Insert the newly created intrinsic to intrinsic_funcs_map_
+    if (!intrinsic_funcs_map_.insert(std::make_pair(fn, id)).second) {
+      LOG(FATAL) << "Duplicate entry in intrinsic functions map?";
+    }
+  }
+
+  return;
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/intrinsic_helper.h b/src/greenland/intrinsic_helper.h
new file mode 100644
index 0000000..a5c2097
--- /dev/null
+++ b/src/greenland/intrinsic_helper.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_INTRINSIC_HELPER_H_
+#define ART_SRC_GREENLAND_INTRINSIC_HELPER_H_
+
+#include "logging.h"
+
+#include <llvm/ADT/DenseMap.h>
+
+namespace llvm {
+  class Function;
+  class FunctionType;
+  class LLVMContext;
+  class Module;
+}
+
+namespace art {
+namespace greenland {
+
+class IRBuilder;
+
+class IntrinsicHelper {
+ public:
+  enum IntrinsicId {
+#define DEF_INTRINSICS_FUNC(ID, ...) ID,
+#include "intrinsic_func_list.def"
+    MaxIntrinsicId,
+
+    // Pseudo-intrinsics Id
+    UnknownId
+  };
+
+  enum IntrinsicAttribute {
+    kAttrNone     = 0,
+
+    // Intrinsic that doesn't modify the memory state
+    kAttrReadOnly = 1 << 0,
+
+    // Intrinsic that never generates exception
+    kAttrNoThrow  = 1 << 1,
+  };
+
+  enum IntrinsicValType {
+    kNone,
+
+    kVoidTy,
+
+    kJavaObjectTy,
+    kJavaMethodTy,
+    kJavaThreadTy,
+
+    kInt1Ty,
+    kInt8Ty,
+    kInt16Ty,
+    kInt32Ty,
+    kInt64Ty,
+
+    kInt1ConstantTy,
+    kInt8ConstantTy,
+    kInt16ConstantTy,
+    kInt32ConstantTy,
+    kInt64ConstantTy,
+
+    kVarArgTy,
+  };
+
+  enum {
+    kIntrinsicMaxArgc = 5
+  };
+
+  typedef struct IntrinsicInfo {
+    const char* name_;
+    unsigned attr_;
+    IntrinsicValType ret_val_type_;
+    IntrinsicValType arg_type_[kIntrinsicMaxArgc];
+  } IntrinsicInfo;
+
+ private:
+  static const IntrinsicInfo Info[MaxIntrinsicId];
+
+ public:
+  static const IntrinsicInfo& GetInfo(IntrinsicId id) {
+    DCHECK(id >= 0 && id < MaxIntrinsicId) << "Unknown Dalvik intrinsics ID: "
+                                           << id;
+    return Info[id];
+  }
+
+  static const char* GetName(IntrinsicId id) {
+    return GetInfo(id).name_;
+  }
+
+  static unsigned GetAttr(IntrinsicId id) {
+    return GetInfo(id).attr_;
+  }
+
+ public:
+  IntrinsicHelper(llvm::LLVMContext& context, llvm::Module& module);
+
+  inline llvm::Function* GetIntrinsicFunction(IntrinsicId id) {
+    DCHECK(id >= 0 && id < MaxIntrinsicId) << "Unknown Dalvik intrinsics ID: "
+                                           << id;
+    return intrinsic_funcs_[id];
+  }
+
+  inline IntrinsicId GetIntrinsicId(const llvm::Function* func) const {
+    llvm::DenseMap<const llvm::Function*, IntrinsicId>::const_iterator
+        i = intrinsic_funcs_map_.find(func);
+    if (i == intrinsic_funcs_map_.end()) {
+      return UnknownId;
+    } else {
+      return i->second;
+    }
+  }
+
+ private:
+  llvm::Function* intrinsic_funcs_[MaxIntrinsicId];
+
+  // Map a llvm::Function to its intrinsic id
+  llvm::DenseMap<const llvm::Function*, IntrinsicId> intrinsic_funcs_map_;
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_INTRINSIC_HELPER_H_
diff --git a/src/greenland/ir_builder.cc b/src/greenland/ir_builder.cc
new file mode 100644
index 0000000..d47a458
--- /dev/null
+++ b/src/greenland/ir_builder.cc
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir_builder.h"
+
+#include <llvm/Module.h>
+
+namespace art {
+namespace greenland {
+
+IRBuilder::IRBuilder(llvm::LLVMContext& context, llvm::Module& module,
+                     IntrinsicHelper& intrinsic_helper)
+    : LLVMIRBuilder(context), java_object_type_(NULL), java_method_type_(NULL),
+      java_thread_type_(NULL), intrinsic_helper_(intrinsic_helper) {
+  java_object_type_ = module.getTypeByName("JavaObject")->getPointerTo();
+  java_method_type_ = module.getTypeByName("Method")->getPointerTo();
+  java_thread_type_ = module.getTypeByName("Thread")->getPointerTo();
+}
+
+llvm::Type* IRBuilder::GetJTypeInAccurateSpace(JType jty) {
+  switch (jty) {
+  case kVoid:
+    return GetJVoidTy();
+
+  case kBoolean:
+    return GetJBooleanTy();
+
+  case kByte:
+    return GetJByteTy();
+
+  case kChar:
+    return GetJCharTy();
+
+  case kShort:
+    return GetJShortTy();
+
+  case kInt:
+    return GetJIntTy();
+
+  case kLong:
+    return GetJLongTy();
+
+  case kFloat:
+    return GetJFloatTy();
+
+  case kDouble:
+    return GetJDoubleTy();
+
+  case kObject:
+    return GetJObjectTy();
+  }
+
+  LOG(FATAL) << "Unknown java type: " << jty;
+  return NULL;
+}
+
+llvm::Type* IRBuilder::GetJTypeInRegSpace(JType jty) {
+  RegCategory regcat = GetRegCategoryFromJType(jty);
+
+  switch (regcat) {
+  case kRegUnknown:
+  case kRegZero:
+    LOG(FATAL) << "Register category \"Unknown\" or \"Zero\" does not have "
+               << "the LLVM type";
+    return NULL;
+
+  case kRegCat1nr:
+    return getInt32Ty();
+
+  case kRegCat2:
+    return getInt64Ty();
+
+  case kRegObject:
+    return GetJObjectTy();
+  }
+
+  LOG(FATAL) << "Unknown register category: " << regcat;
+  return NULL;
+}
+
+llvm::Type* IRBuilder::GetJTypeInArraySpace(JType jty) {
+  switch (jty) {
+  case kVoid:
+    LOG(FATAL) << "void type should not be used in array type space";
+    return NULL;
+
+  case kBoolean:
+  case kByte:
+    return getInt8Ty();
+
+  case kChar:
+  case kShort:
+    return getInt16Ty();
+
+  case kInt:
+    return getInt32Ty();
+
+  case kLong:
+    return getInt64Ty();
+
+  case kFloat:
+    return getFloatTy();
+
+  case kDouble:
+    return getDoubleTy();
+
+  case kObject:
+    return GetJObjectTy();
+  }
+
+  LOG(FATAL) << "Unknown java type: " << jty;
+  return NULL;
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/ir_builder.h b/src/greenland/ir_builder.h
new file mode 100644
index 0000000..a46e4b3
--- /dev/null
+++ b/src/greenland/ir_builder.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_IR_BUILDER_H_
+#define ART_SRC_GREENLAND_IR_BUILDER_H_
+
+#include "backend_types.h"
+#include "intrinsic_helper.h"
+
+#include "logging.h"
+
+#include <llvm/Support/IRBuilder.h>
+
+namespace llvm {
+  class Module;
+}
+
+namespace art {
+namespace greenland {
+
+typedef llvm::IRBuilder<> LLVMIRBuilder;
+
+class IRBuilder : public LLVMIRBuilder {
+ public:
+  IRBuilder(llvm::LLVMContext& context, llvm::Module& module,
+            IntrinsicHelper& intrinsic_helper);
+  ~IRBuilder() { }
+
+ public:
+  //--------------------------------------------------------------------------
+  // Pointer Arithmetic Helper Function
+  //--------------------------------------------------------------------------
+  llvm::IntegerType* GetPtrEquivIntTy() {
+    return getInt32Ty();
+  }
+
+  llvm::ConstantInt* GetPtrEquivInt(int64_t i) {
+    return llvm::ConstantInt::get(GetPtrEquivIntTy(), i);
+  }
+
+  //--------------------------------------------------------------------------
+  // Intrinsic Helper Functions
+  //--------------------------------------------------------------------------
+  llvm::Function* GetIntrinsics(IntrinsicHelper::IntrinsicId instr_id) {
+    return intrinsic_helper_.GetIntrinsicFunction(instr_id);
+  }
+
+  //--------------------------------------------------------------------------
+  // Type Helper Functions
+  //--------------------------------------------------------------------------
+  llvm::Type* GetJType(char shorty_jty, JTypeSpace space) {
+    return GetJType(GetJTypeFromShorty(shorty_jty), space);
+  }
+
+  llvm::Type* GetJType(JType jty, JTypeSpace space) {
+    switch (space) {
+    case kAccurate:
+      return GetJTypeInAccurateSpace(jty);
+
+    case kReg:
+    case kField: // Currently field space is equivalent to register space.
+      return GetJTypeInRegSpace(jty);
+
+    case kArray:
+      return GetJTypeInArraySpace(jty);
+    }
+
+    LOG(FATAL) << "Unknown type space: " << space;
+    return NULL;
+  }
+
+  llvm::Type* GetJVoidTy() {
+    return getVoidTy();
+  }
+
+  llvm::IntegerType* GetJBooleanTy() {
+    return getInt1Ty();
+  }
+
+  llvm::IntegerType* GetJByteTy() {
+    return getInt8Ty();
+  }
+
+  llvm::IntegerType* GetJCharTy() {
+    return getInt16Ty();
+  }
+
+  llvm::IntegerType* GetJShortTy() {
+    return getInt16Ty();
+  }
+
+  llvm::IntegerType* GetJIntTy() {
+    return getInt32Ty();
+  }
+
+  llvm::IntegerType* GetJLongTy() {
+    return getInt64Ty();
+  }
+
+  llvm::Type* GetJFloatTy() {
+    return getFloatTy();
+  }
+
+  llvm::Type* GetJDoubleTy() {
+    return getDoubleTy();
+  }
+
+  llvm::PointerType* GetJObjectTy() {
+    return java_object_type_;
+  }
+
+  llvm::PointerType* GetJMethodTy() {
+    return java_method_type_;
+  }
+
+  llvm::PointerType* GetJThreadTy() {
+    return java_thread_type_;
+  }
+
+  //--------------------------------------------------------------------------
+  // Constant Value Helper Function
+  //--------------------------------------------------------------------------
+  llvm::ConstantInt* GetJBoolean(bool is_true) {
+    return (is_true) ? getTrue() : getFalse();
+  }
+
+  llvm::ConstantInt* GetJByte(int8_t i) {
+    return llvm::ConstantInt::getSigned(GetJByteTy(), i);
+  }
+
+  llvm::ConstantInt* GetJChar(int16_t i) {
+    return llvm::ConstantInt::getSigned(GetJCharTy(), i);
+  }
+
+  llvm::ConstantInt* GetJShort(int16_t i) {
+    return llvm::ConstantInt::getSigned(GetJShortTy(), i);
+  }
+
+  llvm::ConstantInt* GetJInt(int32_t i) {
+    return llvm::ConstantInt::getSigned(GetJIntTy(), i);
+  }
+
+  llvm::ConstantInt* GetJLong(int64_t i) {
+    return llvm::ConstantInt::getSigned(GetJLongTy(), i);
+  }
+
+  llvm::Constant* GetJFloat(float f) {
+    return llvm::ConstantFP::get(GetJFloatTy(), f);
+  }
+
+  llvm::Constant* GetJDouble(double d) {
+    return llvm::ConstantFP::get(GetJDoubleTy(), d);
+  }
+
+  llvm::ConstantPointerNull* GetJNull() {
+    return llvm::ConstantPointerNull::get(GetJObjectTy());
+  }
+
+  llvm::Constant* GetJZero(char shorty_jty) {
+    return GetJZero(GetJTypeFromShorty(shorty_jty));
+  }
+
+  llvm::Constant* GetJZero(JType jty) {
+    switch (jty) {
+    case kVoid:
+      LOG(FATAL) << "Zero is not a value of void type";
+      return NULL;
+
+    case kBoolean:
+      return GetJBoolean(false);
+
+    case kByte:
+      return GetJByte(0);
+
+    case kChar:
+      return GetJChar(0);
+
+    case kShort:
+      return GetJShort(0);
+
+    case kInt:
+      return GetJInt(0);
+
+    case kLong:
+      return GetJLong(0);
+
+    case kFloat:
+      return GetJFloat(0.0f);
+
+    case kDouble:
+      return GetJDouble(0.0);
+
+    case kObject:
+      return GetJNull();
+
+    default:
+      LOG(FATAL) << "Unknown java type: " << jty;
+      return NULL;
+    }
+  }
+
+ private:
+  llvm::Type* GetJTypeInAccurateSpace(JType jty);
+  llvm::Type* GetJTypeInRegSpace(JType jty);
+  llvm::Type* GetJTypeInArraySpace(JType jty);
+
+  llvm::PointerType* java_object_type_;
+  llvm::PointerType* java_method_type_;
+  llvm::PointerType* java_thread_type_;
+
+  IntrinsicHelper& intrinsic_helper_;
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_IR_BUILDER_H_
diff --git a/src/greenland/lir.cc b/src/greenland/lir.cc
new file mode 100644
index 0000000..72fb03b
--- /dev/null
+++ b/src/greenland/lir.cc
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "lir.h"
+
+#include "lir_desc.h"
+#include "lir_function.h"
+
+namespace art {
+namespace greenland {
+
+LIR::LIR(const LIRDesc& desc) : parent_(NULL), desc_(desc) {
+  operands_.reserve(desc_.GetNumOperands());
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/lir.h b/src/greenland/lir.h
new file mode 100644
index 0000000..82116b2
--- /dev/null
+++ b/src/greenland/lir.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_LIR_H_
+#define ART_SRC_GREENLAND_LIR_H_
+
+#include "logging.h"
+#include "macros.h"
+#include "object.h"
+
+#include "lir_desc.h"
+#include "lir_operand.h"
+
+#include <vector>
+
+#include <llvm/ADT/ilist_node.h>
+
+namespace art {
+namespace greenland {
+
+class LIRFunction;
+
+class LIR : public llvm::ilist_node<LIR> {
+ private:
+  // LIRs are allocated and owned by LIRFunction.
+  friend class LIRFunction;
+
+  LIR(const LIRDesc& desc);
+
+  ~LIR() { }
+
+ private:
+  LIRFunction* parent_;
+
+  const LIRDesc& desc_; // Instruction descriptor
+
+  std::vector<LIROperand> operands_;
+
+#if 0
+  struct {
+    bool is_nop:1;          // LIR is optimized away
+    bool pc_rel_fixup:1;    // May need pc-relative fixup
+    unsigned int age:4;     // default is 0, set lazily by the optimizer
+    unsigned int size:5;    // in bytes
+    unsigned int unused:21;
+  } flags_;
+
+  int alias_info_;          // For Dalvik register & litpool disambiguation
+  uint8_t use_mask_;        // Resource mask for use
+  uint8_t def_mask_;        // Resource mask for def
+#endif
+
+ private:
+  // Intrusive list support
+  friend struct llvm::ilist_traits<LIR>;
+  friend struct llvm::ilist_traits<LIRFunction>;
+  void SetParent(LIRFunction *parent) {
+    parent_ = parent;
+  }
+
+ public:
+  const LIRFunction* GetParent() const {
+    return parent_;
+  }
+
+  LIRFunction* GetParent() {
+    return parent_;
+  }
+
+  const LIRDesc& GetDesc() const {
+    return desc_;
+  }
+
+  int GetOpcode() const {
+    return desc_.opcode_;
+  }
+
+ public:
+  //----------------------------------------------------------------------------
+  // Operand Operations
+  //----------------------------------------------------------------------------
+  unsigned GetNumOperands() const {
+    return static_cast<unsigned>(operands_.size());
+  }
+
+  const LIROperand& GetOperand(unsigned i) const {
+    DCHECK(i < GetNumOperands()) << "GetOperand() out of range!";
+    return operands_[i];
+  }
+
+  LIROperand& GetOperand(unsigned i) {
+    DCHECK(i < GetNumOperands()) << "GetOperand() out of range!";
+    return operands_[i];
+  }
+
+  /// iterator/begin/end - Iterate over all operands of a machine instruction.
+  typedef std::vector<LIROperand>::iterator op_iterator;
+  typedef std::vector<LIROperand>::const_iterator const_op_iterator;
+
+  op_iterator operands_begin() { return operands_.begin(); }
+  op_iterator operands_end() { return operands_.end(); }
+
+  const_op_iterator operands_begin() const { return operands_.begin(); }
+  const_op_iterator operands_end() const { return operands_.end(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LIR);
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_LIR_H_
diff --git a/src/greenland/lir_desc.h b/src/greenland/lir_desc.h
new file mode 100644
index 0000000..84b7af6
--- /dev/null
+++ b/src/greenland/lir_desc.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_LIR_DESC_H_
+#define ART_SRC_GREENLAND_LIR_DESC_H_
+
+namespace art {
+namespace greenland {
+
+class LIRDesc {
+ public:
+  unsigned opcode_;             // The opcode number
+  unsigned short num_operands_; // Num of args (may be more if variable_ops)
+
+  unsigned GetOpcode() const {
+    return opcode_;
+  }
+
+  unsigned GetNumOperands() const {
+    return num_operands_;
+  }
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_LIR_DESC_H_
diff --git a/src/greenland/lir_frame_info.h b/src/greenland/lir_frame_info.h
new file mode 100644
index 0000000..ecaa7f3
--- /dev/null
+++ b/src/greenland/lir_frame_info.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_LIR_FRAME_INFO_H_
+#define ART_SRC_GREENLAND_LIR_FRAME_INFO_H_
+
+#include "logging.h"
+
+#include <vector>
+
+namespace art {
+namespace greenland {
+
+class LIRFrameInfo {
+ private:
+  struct StackObject {
+    // The offset from the stack pointer
+    off_t sp_offset_;
+
+    // The object is a dead object if its size is 0
+    size_t size_;
+
+    unsigned alignment_;
+
+    StackObject(size_t size, unsigned alignment)
+        : size_(size), alignment_(alignment) { }
+  };
+
+  // stack_size_ and sp_offset_ in each StackObject will be updated by ...
+  size_t stack_size_;
+
+  std::vector<StackObject> objects_;
+
+ public:
+  LIRFrameInfo() : stack_size_(0) { }
+
+  bool HasStackObjects() const {
+    return !objects_.empty();
+  }
+
+  unsigned GetNumObjects() const {
+    return objects_.size();
+  }
+
+  size_t GetStackSize() const {
+    return stack_size_;
+  }
+  void SetStackSize(size_t stack_size) {
+    stack_size_ = stack_size;
+    return;
+  }
+
+  //----------------------------------------------------------------------------
+  // Stack Object
+  //----------------------------------------------------------------------------
+  size_t GetObjectOffset(unsigned idx) const {
+    DCHECK(idx < GetNumObjects()) << "Invalid frame index!";
+    return objects_[idx].sp_offset_;
+  }
+  void SetObjectOffset(unsigned idx, off_t sp_offset) {
+    DCHECK(idx < GetNumObjects()) << "Invalid frame index!";
+    objects_[idx].sp_offset_ = sp_offset;
+    return;
+  }
+
+  size_t GetObjectSize(unsigned idx) const {
+    DCHECK(idx < GetNumObjects()) << "Invalid frame index!";
+    return objects_[idx].size_;
+  }
+
+  size_t GetObjectAlignment(unsigned idx) const {
+    DCHECK(idx < GetNumObjects()) << "Invalid frame index!";
+    return objects_[idx].alignment_;
+  }
+
+  unsigned AllocateStackObject(size_t size, unsigned alignment = 1) {
+    DCHECK(size > 0);
+    objects_.push_back(StackObject(size, alignment));
+    return objects_.size() - 1;
+  }
+
+  void RemoveStackObject(unsigned idx) {
+    DCHECK(idx < GetNumObjects()) << "Invalid frame index!";
+    objects_[idx].size_ = 0;
+    return;
+  }
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_LIR_FRAME_INFO_H_
diff --git a/src/greenland/lir_function.cc b/src/greenland/lir_function.cc
new file mode 100644
index 0000000..5def2ac
--- /dev/null
+++ b/src/greenland/lir_function.cc
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "lir_function.h"
+
+#include "lir_frame_info.h"
+
+#include "logging.h"
+
+namespace llvm {
+
+using art::greenland::LIR;
+using art::greenland::LIRFunction;
+
+void ilist_traits<LIR>::addNodeToList(LIR* lir) {
+  DCHECK(lir->GetParent() == 0) << "LIR already in a function";
+  // Update the LIR::parent_
+  lir->SetParent(parent_);
+  return;
+}
+
+void ilist_traits<LIR>::removeNodeFromList(LIR* lir) {
+  DCHECK(lir->GetParent() == 0) << "LIR is not in a function";
+  // Update the LIR::parent_
+  lir->SetParent(NULL);
+  return;
+}
+
+void ilist_traits<LIR>::transferNodesFromList(ilist_traits &src_traits,
+                                              ilist_iterator<LIR> first,
+                                              ilist_iterator<LIR> last) {
+  UNIMPLEMENTED(FATAL);
+  return;
+}
+
+void ilist_traits<LIR>::deleteNode(LIR* lir) {
+  CHECK(!lir->GetParent()) << "LIR is still in a block!";
+  parent_->DeleteLIR(lir);
+  return;
+}
+
+} // namespace llvm
+
+namespace art {
+namespace greenland {
+
+LIRFunction::LIRFunction() : frame_info_(NULL) {
+  lirs_.parent_ = this;
+  frame_info_ = new (allocator_) LIRFrameInfo();
+  return;
+}
+
+LIRFunction::~LIRFunction() {
+  lirs_.clear();
+  lir_recycler_.clear(allocator_);
+
+  frame_info_->~LIRFrameInfo();
+  allocator_.Deallocate(frame_info_);
+
+  return;
+}
+
+LIR* LIRFunction::CreateLIR(const LIRDesc& desc) {
+  return new (lir_recycler_.Allocate<LIR>(allocator_)) LIR(desc);
+}
+
+void LIRFunction::DeleteLIR(LIR* lir) {
+  lir->~LIR();
+  lir_recycler_.Deallocate(allocator_, lir);
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/lir_function.h b/src/greenland/lir_function.h
new file mode 100644
index 0000000..0e77f17
--- /dev/null
+++ b/src/greenland/lir_function.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_LIR_FUNCTION_H_
+#define ART_SRC_GREENLAND_LIR_FUNCTION_H_
+
+#include "lir.h"
+
+#include <llvm/ADT/ilist.h>
+#include <llvm/Support/Allocator.h>
+#include <llvm/Support/Recycler.h>
+
+namespace llvm {
+
+template <>
+struct ilist_traits<art::greenland::LIR> :
+    public ilist_default_traits<art::greenland::LIR> {
+ private:
+  mutable ilist_half_node<art::greenland::LIR> sentinel_;
+
+  friend class art::greenland::LIRFunction;
+  art::greenland::LIRFunction* parent_;
+
+ public:
+  art::greenland::LIR *createSentinel() const {
+    return static_cast<art::greenland::LIR*>(&sentinel_);
+  }
+  void destroySentinel(art::greenland::LIR *) const {}
+
+  art::greenland::LIR *provideInitialHead() const {
+    return createSentinel();
+  }
+  art::greenland::LIR *ensureHead(art::greenland::LIR*) const {
+    return createSentinel();
+  }
+  static void noteHead(art::greenland::LIR*, art::greenland::LIR*) {}
+
+  void addNodeToList(art::greenland::LIR* N);
+  void removeNodeFromList(art::greenland::LIR* N);
+  void transferNodesFromList(ilist_traits &src_traits,
+                             ilist_iterator<art::greenland::LIR> first,
+                             ilist_iterator<art::greenland::LIR> last);
+  void deleteNode(art::greenland::LIR *N);
+private:
+  void createNode(const art::greenland::LIR &);
+};
+
+} // namespace llvm
+
+namespace art {
+namespace greenland {
+
+class LIRFrameInfo;
+
+class LIRFunction {
+ private:
+  llvm::ilist<LIR> lirs_;
+
+  // Pool-allocate the objects reside in this instance
+  llvm::BumpPtrAllocator allocator_;
+
+  // Allocation management for instructions in function.
+  llvm::Recycler<LIR> lir_recycler_;
+
+  // The stack information
+  LIRFrameInfo* frame_info_;
+
+ public:
+  LIRFunction();
+  ~LIRFunction();
+
+ public:
+  //----------------------------------------------------------------------------
+  // LIR Accessor Functions
+  //----------------------------------------------------------------------------
+  typedef llvm::ilist<LIR>::iterator                          iterator;
+  typedef llvm::ilist<LIR>::const_iterator              const_iterator;
+  typedef std::reverse_iterator<iterator>             reverse_iterator;
+  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+  unsigned GetNumLIRs() const {
+    return static_cast<unsigned>(lirs_.size());
+  }
+  bool IsEmpty() const {
+    return lirs_.empty();
+  }
+
+  LIR& front() { return lirs_.front(); }
+  LIR& back()  { return lirs_.back(); }
+  const LIR& front() const { return lirs_.front(); }
+  const LIR& back()  const { return lirs_.back(); }
+
+  iterator                begin()       { return lirs_.begin();  }
+  const_iterator          begin() const { return lirs_.begin();  }
+  iterator                  end()       { return lirs_.end();    }
+  const_iterator            end() const { return lirs_.end();    }
+  reverse_iterator       rbegin()       { return lirs_.rbegin(); }
+  const_reverse_iterator rbegin() const { return lirs_.rbegin(); }
+  reverse_iterator       rend  ()       { return lirs_.rend();   }
+  const_reverse_iterator rend  () const { return lirs_.rend();   }
+
+  void pop_front() {
+    lirs_.pop_front();
+  }
+
+  void push_back(LIR *lir) {
+    lirs_.push_back(lir);
+  }
+
+  iterator insert(iterator i, LIR* lir) {
+    return lirs_.insert(i, lir);
+  }
+
+  iterator erase(iterator i) {
+    return lirs_.erase(i);
+  }
+
+  LIR* remove(iterator i) {
+    return lirs_.remove(i);
+  }
+
+ public:
+  //----------------------------------------------------------------------------
+  // LIR Memory Allocation
+  //----------------------------------------------------------------------------
+  LIR* CreateLIR(const LIRDesc& desc);
+
+  void DeleteLIR(LIR* lir);
+
+ public:
+  const LIRFrameInfo& GetFrameInfo() const {
+    return *frame_info_;
+  }
+  LIRFrameInfo& GetFrameInfo() {
+    return *frame_info_;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LIRFunction);
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_LIR_FUNCTION_H_
diff --git a/src/greenland/lir_operand.h b/src/greenland/lir_operand.h
new file mode 100644
index 0000000..d6d9232
--- /dev/null
+++ b/src/greenland/lir_operand.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_LIR_OPERAND_H_
+#define ART_SRC_GREENLAND_LIR_OPERAND_H_
+
+#include "logging.h"
+
+namespace llvm {
+  class ConstantFP;
+}
+
+namespace art {
+namespace greenland {
+
+class LIR;
+
+class LIROperand {
+ public:
+  enum Type {
+    UnknownType,
+    RegisterType,
+    ImmediateType,
+    FPImmediateType,
+    LabelType,
+  };
+
+ private:
+  Type type_;
+
+  union {
+    // RegisterType
+    unsigned reg_no_;
+
+    // ImmediateType
+    int64_t imm_val_;
+
+    // FPImmediateType
+    const llvm::ConstantFP *fp_imm_val_;
+
+    // LabelType
+    const LIR* target_;
+  } contents_;
+
+  friend class LIR;
+  LIROperand() : type_(UnknownType) { }
+
+  void SetType(enum Type type) {
+    type_ = type;
+    return;
+  }
+
+ public:
+  enum Type GetType() const {
+    return type_;
+  }
+
+  bool IsReg() const {
+    return (type_ == RegisterType);
+  }
+  bool IsImm() const {
+    return (type_ == ImmediateType);
+  }
+  bool IsFPImm() const {
+    return (type_ == FPImmediateType);
+  }
+  bool IsLabel() const {
+    return (type_ == LabelType);
+  }
+
+  //----------------------------------------------------------------------------
+  //  Accessors
+  //----------------------------------------------------------------------------
+  unsigned GetReg() const {
+    CHECK(IsReg()) << "This is not a register operand!";
+    return contents_.reg_no_;
+  }
+
+  int64_t GetImm() const {
+    CHECK(IsImm()) << "This is not a immediate operand!";
+    return contents_.imm_val_;
+  }
+
+  const llvm::ConstantFP* GetFPImm() const {
+    CHECK(IsFPImm()) << "This is not a FP immediate operand!";
+    return contents_.fp_imm_val_;
+  }
+
+  const LIR* GetLabelTarget() const {
+    CHECK(IsFPImm()) << "This is not a label operand!";
+    return contents_.target_;
+  }
+
+  //----------------------------------------------------------------------------
+  //  Mutators
+  //----------------------------------------------------------------------------
+  void SetReg(unsigned reg_no) {
+    if (type_ == UnknownType) {
+      type_ = RegisterType;
+    }
+    CHECK(IsReg()) << "This is not a register operand!";
+    contents_.reg_no_ = reg_no;
+    return;
+  }
+
+  void SetImm(int64_t imm_val) {
+    if (type_ == UnknownType) {
+      type_ = ImmediateType;
+    }
+    CHECK(IsImm()) << "This is not a immediate operand!";
+    contents_.imm_val_ = imm_val;
+    return;
+  }
+
+  void SetFPImm(const llvm::ConstantFP* fp_imm_val) {
+    if (type_ == UnknownType) {
+      type_ = FPImmediateType;
+    }
+    CHECK(IsFPImm()) << "This is not a FP immediate operand!";
+    contents_.fp_imm_val_ = fp_imm_val;
+    return;
+  }
+
+  void SetLabelTarget(LIR* target) {
+    if (type_ == UnknownType) {
+      type_ = LabelType;
+    }
+    CHECK(IsLabel()) << "This is not a label operand!";
+    contents_.target_ = target;
+    return;
+  }
+
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_LIR_OPERAND_H_
diff --git a/src/greenland/mips/mips_codegen_machine.cc b/src/greenland/mips/mips_codegen_machine.cc
new file mode 100644
index 0000000..c63718b
--- /dev/null
+++ b/src/greenland/mips/mips_codegen_machine.cc
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mips_codegen_machine.h"
+
+#include "greenland/target_registry.h"
+
+namespace art {
+namespace greenland {
+
+MipsCodeGenMachine::MipsCodeGenMachine() {
+}
+
+MipsCodeGenMachine::~MipsCodeGenMachine() {
+}
+
+void InitializeMipsCodeGenMachine() {
+  RegisterTargetCodeGenMachine<MipsCodeGenMachine> X(kMips);
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/mips/mips_codegen_machine.h b/src/greenland/mips/mips_codegen_machine.h
new file mode 100644
index 0000000..e3412e9
--- /dev/null
+++ b/src/greenland/mips/mips_codegen_machine.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_MIPS_CODEGEN_MACHINE_H_
+#define ART_SRC_GREENLAND_MIPS_CODEGEN_MACHINE_H_
+
+#include "greenland/target_codegen_machine.h"
+
+namespace art {
+namespace greenland {
+
+class MipsCodeGenMachine : public TargetCodeGenMachine {
+ private:
+
+ public:
+  MipsCodeGenMachine();
+  virtual ~MipsCodeGenMachine();
+
+  virtual TargetLIREmitter* CreateLIREmitter(const llvm::Function& func,
+                                             const OatCompilationUnit& cunit,
+                                             DexLang::Context& dex_lang_ctx) {
+    return NULL;
+  }
+
+  virtual RegisterAllocator* GetRegisterAllocator() {
+    return NULL;
+  }
+
+  virtual TargetAssembler* GetAssembler() {
+    return NULL;
+  }
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_MIPS_CODEGEN_MACHINE_H_
diff --git a/src/greenland/mips/mips_invoke_stub_compiler.cc b/src/greenland/mips/mips_invoke_stub_compiler.cc
new file mode 100644
index 0000000..e7aa662
--- /dev/null
+++ b/src/greenland/mips/mips_invoke_stub_compiler.cc
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "greenland/target_registry.h"
+
+#include "logging.h"
+
+namespace art {
+  class Compiler;
+  class CompiledInvokeStub;
+}
+
+namespace {
+
+art::CompiledInvokeStub* MipsInvokeStubCompiler(art::Compiler& /*compiler*/,
+                                                bool is_static,
+                                                const char* shorty,
+                                                uint32_t shorty_len) {
+  UNIMPLEMENTED(FATAL);
+  return NULL;
+}
+
+} // anonymous namespace
+
+namespace art {
+namespace greenland {
+
+void InitializeMipsInvokeStubCompiler() {
+  TargetRegistry::RegisterInvokeStubCompiler(kMips, MipsInvokeStubCompiler);
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/target_codegen_machine.cc b/src/greenland/target_codegen_machine.cc
new file mode 100644
index 0000000..87a215e
--- /dev/null
+++ b/src/greenland/target_codegen_machine.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "target_codegen_machine.h"
+
+#include "greenland.h"
+#include "target_lir_emitter.h"
+#include "target_registry.h"
+
+#include "compiled_method.h"
+#include "compiler.h"
+
+#include <UniquePtr.h>
+
+namespace art {
+namespace greenland {
+
+TargetCodeGenMachine* TargetCodeGenMachine::Create(InstructionSet insn_set) {
+  TargetRegistry::TargetCodeGenMachineCtorTy ctor =
+      TargetRegistry::GetTargetCodeGenMachineCtor(insn_set);
+
+  if (ctor == NULL) {
+    return NULL;
+  }
+
+  return (*ctor)();
+}
+
+CompiledMethod* TargetCodeGenMachine::Run(const Greenland& parent,
+                                          const llvm::Function& func,
+                                          const OatCompilationUnit& cunit,
+                                          DexLang::Context& dex_lang_ctx) {
+#if 0
+  UniquePtr<TargetLIREmitter> emitter(CreateLIREmitter(func, cunit,
+                                                       dex_lang_ctx));
+  LIRFunction* lir_func = emitter->Emit();
+  if (lir_func == NULL) {
+    return NULL;
+  }
+#endif
+
+  // 0x90 is the NOP in x86
+  std::vector<uint8_t> code(10, 0x90);
+
+  return new CompiledMethod(parent.GetCompiler().GetInstructionSet(), code,
+                            /* frame_size_in_bytes */0,
+                            /* core_spill_mask */0,
+                            /* fp_spill_mask */0);
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/target_codegen_machine.h b/src/greenland/target_codegen_machine.h
new file mode 100644
index 0000000..a0962fe
--- /dev/null
+++ b/src/greenland/target_codegen_machine.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_TARGET_CODEGEN_MACHINE_H_
+#define ART_SRC_GREENLAND_TARGET_CODEGEN_MACHINE_H_
+
+#include "dex_lang.h"
+
+#include "instruction_set.h"
+
+namespace art {
+  class CompiledMethod;
+  class OatCompilationUnit;
+}
+
+namespace llvm {
+  class Function;
+}
+
+namespace art {
+namespace greenland {
+
+class Greenland;
+class TargetLIREmitter;
+class RegisterAllocator;
+class TargetAssembler;
+
+class TargetCodeGenMachine {
+ protected:
+  TargetCodeGenMachine() { }
+
+ public:
+  virtual ~TargetCodeGenMachine() { }
+
+  virtual TargetLIREmitter* CreateLIREmitter(const llvm::Function& func,
+                                             const OatCompilationUnit& cunit,
+                                             DexLang::Context& dex_lang_ctx) =0;
+
+  virtual RegisterAllocator* GetRegisterAllocator() = 0;
+
+  virtual TargetAssembler* GetAssembler() = 0;
+
+  static TargetCodeGenMachine* Create(InstructionSet insn_set);
+
+ public:
+  CompiledMethod* Run(const Greenland& parent,
+                      const llvm::Function& func,
+                      const OatCompilationUnit& cunit,
+                      DexLang::Context& dex_lang_ctx);
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_TARGET_CODEGEN_MACHINE_H_
diff --git a/src/greenland/target_lir.def b/src/greenland/target_lir.def
new file mode 100644
index 0000000..a3838c6
--- /dev/null
+++ b/src/greenland/target_lir.def
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// DEF_LIR_DESC(OPCODE, NUM_OPS)
+#ifndef DEF_LIR_DESC
+# error "missing DEF_LIR_DESC definition!"
+#endif
+
+DEF_LIR_DESC(kBlockLabel, 1)
diff --git a/src/greenland/target_lir_emitter.cc b/src/greenland/target_lir_emitter.cc
new file mode 100644
index 0000000..babb114
--- /dev/null
+++ b/src/greenland/target_lir_emitter.cc
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "target_lir_emitter.h"
+
+#include "target_lir_info.h"
+#include "target_lir_opcodes.h"
+
+#include "intrinsic_helper.h"
+#include "lir_function.h"
+
+#include <llvm/Function.h>
+
+namespace art {
+namespace greenland {
+
+TargetLIREmitter::TargetLIREmitter(const llvm::Function& func,
+                                   const OatCompilationUnit& cunit,
+                                   DexLang::Context& dex_lang_ctx,
+                                   TargetLIRInfo& target_lir_info)
+    : func_(func), cunit_(cunit), dex_lang_ctx_(dex_lang_ctx.IncRef()),
+      info_(target_lir_info), lir_func_() {
+  return;
+}
+
+TargetLIREmitter::~TargetLIREmitter() {
+  dex_lang_ctx_.DecRef();
+  return;
+}
+
+bool TargetLIREmitter::visitBasicBlock(const llvm::BasicBlock& bb) {
+  // Place the corresponding block label to the output
+  llvm::DenseMap<const llvm::BasicBlock*, LIR*>::const_iterator label_iter =
+      block_labels_.find(&bb);
+
+  DCHECK(label_iter != block_labels_.end());
+  lir_func_.push_back(label_iter->second);
+
+  // Now, iterate over and process all instructions within the basic block
+  for (llvm::BasicBlock::const_iterator inst_iter = bb.begin(),
+          inst_end = bb.end(); inst_iter != inst_end; inst_iter++) {
+    const llvm::Instruction& inst = *inst_iter;
+    switch (inst.getOpcode()) {
+#define VISIT(OPCODE, CLASS)                                          \
+      case llvm::Instruction::OPCODE: {                               \
+        if (!visit ## CLASS(static_cast<const llvm::CLASS&>(inst))) { \
+          return false;                                               \
+        }                                                             \
+        break;                                                        \
+      }
+
+      VISIT(Ret,      ReturnInst);
+      VISIT(Br,       BranchInst);
+      VISIT(ICmp,     ICmpInst);
+      VISIT(IntToPtr, IntToPtrInst);
+      VISIT(Call,     CallInst);
+
+#undef VISIT
+      default : {
+        LOG(INFO) << "Unhandled instruction hit!";
+        inst.dump();
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+bool TargetLIREmitter::visitReturnInst(const llvm::ReturnInst& inst) {
+  inst.dump();
+  return true;
+}
+
+bool TargetLIREmitter::visitBranchInst(const llvm::BranchInst& inst) {
+  inst.dump();
+  return true;
+}
+
+bool TargetLIREmitter::visitICmpInst(const llvm::ICmpInst& inst) {
+  inst.dump();
+  return true;
+}
+
+bool TargetLIREmitter::visitIntToPtrInst(const llvm::IntToPtrInst& inst) {
+  inst.dump();
+  return true;
+}
+
+bool TargetLIREmitter::visitCallInst(const llvm::CallInst& inst) {
+  // The callee must be a DexLang intrinsic
+  return visitDexLangIntrinsics(inst);
+}
+
+bool TargetLIREmitter::visitDexLangIntrinsics(const llvm::CallInst& inst) {
+  const llvm::Function* callee = inst.getCalledFunction();
+  IntrinsicHelper::IntrinsicId intr_id =
+      dex_lang_ctx_.GetIntrinsicHelper().GetIntrinsicId(callee);
+
+  if (intr_id == IntrinsicHelper::UnknownId) {
+    LOG(INFO) << "Unexpected call instruction to '"
+              << callee->getName().str() << "'";
+    return false;
+  }
+
+  //const IntrinsicHelper::IntrinsicInfo& intr_info =
+  //    IntrinsicHelper::GetInfo(intr_id);
+
+
+  return true;
+}
+
+LIRFunction* TargetLIREmitter::Emit() {
+  if (EmitBasicBlockLabels() &&
+      EmitEntrySequence() &&
+      EmitInstructions() &&
+      EmitExitSequence()) {
+    return &lir_func_;
+  }
+
+  return NULL;
+}
+
+bool TargetLIREmitter::EmitBasicBlockLabels() {
+  for (llvm::Function::const_iterator bb_iter = func_.begin(),
+          bb_end = func_.end(); bb_iter != bb_end; bb_iter++) {
+    LIR* lir = lir_func_.CreateLIR(info_.GetLIRDesc(opcode::kBlockLabel));
+    CHECK(block_labels_.insert(std::make_pair(bb_iter, lir)).second);
+  }
+  return true;
+}
+
+bool TargetLIREmitter::EmitEntrySequence() {
+  // Flush all function arguments to the virtual registers
+  return true;
+}
+
+bool TargetLIREmitter::EmitInstructions() {
+  // Iterator over all basic blocks
+  for (llvm::Function::const_iterator bb_iter = func_.begin(),
+          bb_end = func_.end(); bb_iter != bb_end; bb_iter++) {
+    if (!visitBasicBlock(*bb_iter)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool TargetLIREmitter::EmitExitSequence() {
+  return true;
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/target_lir_emitter.h b/src/greenland/target_lir_emitter.h
new file mode 100644
index 0000000..8e39e4c
--- /dev/null
+++ b/src/greenland/target_lir_emitter.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_TARGET_LIR_EMITTER_H_
+#define ART_SRC_GREENLAND_TARGET_LIR_EMITTER_H_
+
+#include "dex_lang.h"
+
+#include "lir_function.h"
+
+#include <llvm/ADT/DenseMap.h>
+
+namespace art {
+  class OatCompilationUnit;
+}
+
+namespace llvm {
+  class BasicBlock;
+  class BranchInst;
+  class CallInst;
+  class Function;
+  class ICmpInst;
+  class Instruction;
+  class IntToPtrInst;
+  class ReturnInst;
+}
+
+namespace art {
+namespace greenland {
+
+class LIRFunction;
+class TargetLIRInfo;
+
+class TargetLIREmitter {
+ private:
+  const llvm::Function& func_;
+  const OatCompilationUnit& cunit_;
+  DexLang::Context& dex_lang_ctx_;
+  TargetLIRInfo& info_;
+
+ private:
+  llvm::DenseMap<const llvm::BasicBlock*, LIR*> block_labels_;
+
+ protected:
+  LIRFunction lir_func_;
+
+  TargetLIREmitter(const llvm::Function& func,
+                   const OatCompilationUnit& cunit,
+                   DexLang::Context& dex_lang_ctx,
+                   TargetLIRInfo& target_lir_info);
+
+ private:
+  bool visitBasicBlock(const llvm::BasicBlock& bb);
+
+  bool visitReturnInst(const llvm::ReturnInst& inst);
+  bool visitBranchInst(const llvm::BranchInst& inst);
+  //bool visitSwitchInst(SwitchInst &I)            { DELEGATE(TerminatorInst);}
+  //bool visitIndirectBrInst(IndirectBrInst &I)    { DELEGATE(TerminatorInst);}
+  //bool visitInvokeInst(InvokeInst &I)            { DELEGATE(TerminatorInst);}
+  //bool visitResumeInst(ResumeInst &I)            { DELEGATE(TerminatorInst);}
+  //bool visitUnreachableInst(UnreachableInst &I)  { DELEGATE(TerminatorInst);}
+  bool visitICmpInst(const llvm::ICmpInst& inst);
+  //bool visitFCmpInst(FCmpInst &I)                { DELEGATE(CmpInst);}
+  //bool visitAllocaInst(AllocaInst &I)            { DELEGATE(UnaryInstruction);}
+  //bool visitLoadInst(LoadInst     &I)            { DELEGATE(UnaryInstruction);}
+  //bool visitStoreInst(StoreInst   &I)            { DELEGATE(Instruction);}
+  //bool visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) { DELEGATE(Instruction);}
+  //bool visitAtomicRMWInst(AtomicRMWInst &I)      { DELEGATE(Instruction);}
+  //bool visitFenceInst(FenceInst   &I)            { DELEGATE(Instruction);}
+  //bool visitGetElementPtrInst(GetElementPtrInst &I){ DELEGATE(Instruction);}
+  //bool visitPHINode(PHINode       &I)            { DELEGATE(Instruction);}
+  //bool visitTruncInst(TruncInst &I)              { DELEGATE(CastInst);}
+  //bool visitZExtInst(ZExtInst &I)                { DELEGATE(CastInst);}
+  //bool visitSExtInst(SExtInst &I)                { DELEGATE(CastInst);}
+  //bool visitFPTruncInst(FPTruncInst &I)          { DELEGATE(CastInst);}
+  //bool visitFPExtInst(FPExtInst &I)              { DELEGATE(CastInst);}
+  //bool visitFPToUIInst(FPToUIInst &I)            { DELEGATE(CastInst);}
+  //bool visitFPToSIInst(FPToSIInst &I)            { DELEGATE(CastInst);}
+  //bool visitUIToFPInst(UIToFPInst &I)            { DELEGATE(CastInst);}
+  //bool visitSIToFPInst(SIToFPInst &I)            { DELEGATE(CastInst);}
+  //bool visitPtrToIntInst(PtrToIntInst &I)        { DELEGATE(CastInst);}
+  bool visitIntToPtrInst(const llvm::IntToPtrInst& inst);
+  //bool visitBitCastInst(BitCastInst &I)          { DELEGATE(CastInst);}
+  //bool visitSelectInst(SelectInst &I)            { DELEGATE(Instruction);}
+  bool visitCallInst(const llvm::CallInst& inst);
+  //bool visitVAArgInst(VAArgInst   &I)            { DELEGATE(UnaryInstruction);}
+  //bool visitExtractElementInst(ExtractElementInst &I) { DELEGATE(Instruction);}
+  //bool visitInsertElementInst(InsertElementInst &I) { DELEGATE(Instruction);}
+  //bool visitShuffleVectorInst(ShuffleVectorInst &I) { DELEGATE(Instruction);}
+  //bool visitExtractValueInst(ExtractValueInst &I){ DELEGATE(UnaryInstruction);}
+  //bool visitInsertValueInst(InsertValueInst &I)  { DELEGATE(Instruction); }
+  //bool visitLandingPadInst(LandingPadInst &I)    { DELEGATE(Instruction); }
+
+  bool visitDexLangIntrinsics(const llvm::CallInst& inst);
+
+ public:
+  virtual ~TargetLIREmitter();
+
+  LIRFunction* Emit();
+
+ private:
+  bool EmitBasicBlockLabels();
+  bool EmitEntrySequence();
+  bool EmitInstructions();
+  bool EmitExitSequence();
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_TARGET_LIR_EMITTER_H_
diff --git a/src/greenland/target_lir_info.h b/src/greenland/target_lir_info.h
new file mode 100644
index 0000000..1ed86fa
--- /dev/null
+++ b/src/greenland/target_lir_info.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_TARGET_LIR_INFO_H_
+#define ART_SRC_GREENLAND_TARGET_LIR_INFO_H_
+
+#include "lir_desc.h"
+
+#include "logging.h"
+
+namespace art {
+namespace greenland {
+
+class TargetLIRInfo {
+ private:
+  // An array of target's LIR instruction description
+  const LIRDesc* desc_;
+
+  unsigned num_desc_;
+
+ public:
+  TargetLIRInfo(const LIRDesc* desc, unsigned num_desc)
+      : desc_(desc), num_desc_(num_desc) {
+  }
+
+  virtual ~TargetLIRInfo() { }
+
+  const LIRDesc& GetLIRDesc(unsigned opcode) {
+    DCHECK(opcode < num_desc_) << "Invalid opcode: " << opcode;
+    return desc_[opcode];
+  }
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_TARGET_LIR_INFO_H_
diff --git a/src/greenland/target_lir_opcodes.h b/src/greenland/target_lir_opcodes.h
new file mode 100644
index 0000000..27027ca
--- /dev/null
+++ b/src/greenland/target_lir_opcodes.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_TARGET_LIR_OPCODES_H_
+#define ART_SRC_GREENLAND_TARGET_LIR_OPCODES_H_
+
+namespace art {
+namespace greenland {
+namespace opcode {
+
+enum {
+#define DEF_LIR_DESC(OPCODE, ...) OPCODE,
+#include "target_lir.def"
+#undef DEF_LIR_DESC
+};
+
+} // namespace opcode
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_TARGET_LIR_OPCODES_H_
diff --git a/src/greenland/target_registry.cc b/src/greenland/target_registry.cc
new file mode 100644
index 0000000..e4a1840
--- /dev/null
+++ b/src/greenland/target_registry.cc
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "target_registry.h"
+
+#include "logging.h"
+
+namespace {
+
+// The following arrays contain the real registry data store by Register*()
+// methods in TargetRegistry. Should keep sync with enum InstructionSet.
+art::greenland::TargetRegistry::TargetCodeGenMachineCtorTy
+RegisteredTargetCodeGenMachineCtor[] = {
+  NULL, /* kNone   */
+  NULL, /* kArm    */
+  NULL, /* kThumb2 */
+  NULL, /* kX86    */
+  NULL, /* kMips   */
+};
+
+art::greenland::TargetRegistry::CreateInvokeStubFn
+RegisteredInvokeStubCompiler[] = {
+  NULL, /* kNone   */
+  NULL, /* kArm    */
+  NULL, /* kThumb2 */
+  NULL, /* kX86    */
+  NULL, /* kMips   */
+};
+
+} // anonymous namespace
+
+namespace art {
+namespace greenland {
+
+void TargetRegistry::RegisterTargetCodeGenMachine(InstructionSet insn_set,
+                                            TargetCodeGenMachineCtorTy ctor) {
+  CHECK(static_cast<unsigned>(insn_set) <
+          (sizeof(RegisteredTargetCodeGenMachineCtor) / sizeof(RegisteredTargetCodeGenMachineCtor[0])));
+  RegisteredTargetCodeGenMachineCtor[static_cast<unsigned>(insn_set)] = ctor;
+  return;
+}
+
+TargetRegistry::TargetCodeGenMachineCtorTy
+TargetRegistry::GetTargetCodeGenMachineCtor(InstructionSet insn_set) {
+  CHECK(static_cast<unsigned>(insn_set) <
+          (sizeof(RegisteredTargetCodeGenMachineCtor) / sizeof(RegisteredTargetCodeGenMachineCtor[0])));
+  return RegisteredTargetCodeGenMachineCtor[static_cast<unsigned>(insn_set)];
+}
+
+void
+TargetRegistry::RegisterInvokeStubCompiler(InstructionSet insn_set,
+                                           CreateInvokeStubFn compiler_fn) {
+  CHECK(static_cast<unsigned>(insn_set) <
+        (sizeof(RegisteredInvokeStubCompiler) / sizeof(RegisteredInvokeStubCompiler[0])));
+  RegisteredInvokeStubCompiler[static_cast<unsigned>(insn_set)] = compiler_fn;
+  return;
+}
+
+TargetRegistry::CreateInvokeStubFn
+TargetRegistry::GetInvokeStubCompiler(InstructionSet insn_set) {
+  CHECK(static_cast<unsigned>(insn_set) <
+        (sizeof(RegisteredInvokeStubCompiler) / sizeof(RegisteredInvokeStubCompiler[0])));
+  return RegisteredInvokeStubCompiler[static_cast<unsigned>(insn_set)];
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/target_registry.h b/src/greenland/target_registry.h
new file mode 100644
index 0000000..1f93665
--- /dev/null
+++ b/src/greenland/target_registry.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_TARGET_REGISTRY_H_
+#define ART_SRC_GREENLAND_TARGET_REGISTRY_H_
+
+#include "instruction_set.h"
+
+#include <stdint.h>
+
+namespace art {
+  class Compiler;
+  class CompiledInvokeStub;
+}
+
+namespace art {
+namespace greenland {
+
+class TargetCodeGenMachine;
+
+class TargetRegistry {
+ public:
+  typedef TargetCodeGenMachine* (*TargetCodeGenMachineCtorTy)();
+  typedef CompiledInvokeStub* (*CreateInvokeStubFn)(Compiler& compiler,
+                                                    bool is_static,
+                                                    const char* shorty,
+                                                    uint32_t shorty_len);
+
+  static void RegisterTargetCodeGenMachine(InstructionSet insn_set,
+                                     TargetCodeGenMachineCtorTy ctor);
+  static TargetCodeGenMachineCtorTy GetTargetCodeGenMachineCtor(InstructionSet insn_set);
+
+  static void RegisterInvokeStubCompiler(InstructionSet insn_set,
+                                         CreateInvokeStubFn compiler_fn);
+  static CreateInvokeStubFn GetInvokeStubCompiler(InstructionSet insn_set);
+};
+
+template<class TargetCodeGenMachineImpl>
+class RegisterTargetCodeGenMachine {
+ private:
+  static TargetCodeGenMachine* Allocator() {
+    return new TargetCodeGenMachineImpl();
+  }
+
+ public:
+  RegisterTargetCodeGenMachine(InstructionSet insn_set) {
+    TargetRegistry::RegisterTargetCodeGenMachine(insn_set, &Allocator);
+  }
+};
+
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_TARGET_REGISTRY_H_
diff --git a/src/greenland/x86/x86_codegen_machine.cc b/src/greenland/x86/x86_codegen_machine.cc
new file mode 100644
index 0000000..fe4bd83
--- /dev/null
+++ b/src/greenland/x86/x86_codegen_machine.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "x86_codegen_machine.h"
+
+#include "x86_lir_emitter.h"
+
+#include "greenland/target_registry.h"
+
+namespace art {
+namespace greenland {
+
+void InitializeX86CodeGenMachine() {
+  RegisterTargetCodeGenMachine<X86CodeGenMachine> X(kX86);
+}
+
+X86CodeGenMachine::X86CodeGenMachine() : lir_info_() {
+}
+
+X86CodeGenMachine::~X86CodeGenMachine() {
+}
+
+TargetLIREmitter*
+X86CodeGenMachine::CreateLIREmitter(const llvm::Function& func,
+                                    const OatCompilationUnit& cunit,
+                                    DexLang::Context& dex_lang_ctx) {
+  return new X86LIREmitter(func, cunit, dex_lang_ctx, lir_info_);
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/x86/x86_codegen_machine.h b/src/greenland/x86/x86_codegen_machine.h
new file mode 100644
index 0000000..1b9ac4d
--- /dev/null
+++ b/src/greenland/x86/x86_codegen_machine.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_X86_CODEGEN_MACHINE_H_
+#define ART_SRC_GREENLAND_X86_CODEGEN_MACHINE_H_
+
+#include "greenland/target_codegen_machine.h"
+
+#include "x86_lir_info.h"
+
+namespace art {
+namespace greenland {
+
+class X86CodeGenMachine : public TargetCodeGenMachine {
+ private:
+  X86LIRInfo lir_info_;
+
+ public:
+  X86CodeGenMachine();
+
+  virtual ~X86CodeGenMachine();
+
+  virtual TargetLIREmitter* CreateLIREmitter(const llvm::Function& func,
+                                             const OatCompilationUnit& cunit,
+                                             DexLang::Context& dex_lang_ctx);
+
+  virtual RegisterAllocator* GetRegisterAllocator() {
+    return NULL;
+  }
+
+  virtual TargetAssembler* GetAssembler() {
+    return NULL;
+  }
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_X86_CODEGEN_MACHINE_H_
diff --git a/src/greenland/x86/x86_invoke_stub_compiler.cc b/src/greenland/x86/x86_invoke_stub_compiler.cc
new file mode 100644
index 0000000..18a7765
--- /dev/null
+++ b/src/greenland/x86/x86_invoke_stub_compiler.cc
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "compiled_method.h"
+#include "compiler.h"
+#include "greenland/target_registry.h"
+#include "oat/utils/assembler.h"
+#include "oat/utils/x86/assembler_x86.h"
+#include "object.h"
+
+using namespace art;
+using namespace art::x86;
+
+namespace {
+
+// Creates a function which invokes a managed method with an array of
+// arguments.
+//
+// Immediately after the call on X86, the environment looks like this:
+//
+// [SP+0 ] = Return address
+// [SP+4 ] = method pointer
+// [SP+8 ] = receiver pointer or NULL for static methods
+// [SP+12] = (managed) thread pointer
+// [SP+16] = argument array or NULL for no argument methods
+// [SP+20] = JValue* result or NULL for void returns
+//
+// As the JNI call has already transitioned the thread into the
+// "running" state the remaining responsibilities of this routine are
+// to save the native registers and set up the managed registers. On
+// return, the return value must be store into the result JValue.
+CompiledInvokeStub* CreateInvokeStub(bool is_static, const char* shorty, uint32_t shorty_len) {
+  UniquePtr<X86Assembler> assembler(down_cast<X86Assembler*>(Assembler::Create(kX86)));
+#define __ assembler->
+  size_t num_arg_array_bytes = NumArgArrayBytes(shorty, shorty_len);
+  // Size of frame = return address + saved EBX + Method* + possible receiver + arg array size
+  // Note, space is left in the frame to flush arguments in registers back to out locations.
+  size_t frame_size = 3 * kPointerSize + (is_static ? 0 : kPointerSize) + num_arg_array_bytes;
+  size_t pad_size = RoundUp(frame_size, kStackAlignment) - frame_size;
+
+  Register rMethod = EAX;
+  __ movl(rMethod,   Address(ESP, 4));     // EAX = method
+  Register rReceiver = ECX;
+  if (!is_static) {
+    __ movl(rReceiver, Address(ESP, 8));   // ECX = receiver
+  }
+  // Save EBX
+  __ pushl(EBX);
+  Register rArgArray = EBX;
+  __ movl(rArgArray, Address(ESP, 20));    // EBX = arg array
+
+  // TODO: optimize the frame set up to avoid excessive SP math
+  // Push padding
+  if (pad_size != 0) {
+    __ subl(ESP, Immediate(pad_size));
+  }
+  // Push/copy arguments.
+  size_t arg_count = (shorty_len - 1);
+  size_t dst_offset = num_arg_array_bytes;
+  size_t src_offset = arg_count * sizeof(JValue);
+  for (size_t i = shorty_len - 1; i > 0; --i) {
+    switch (shorty[i]) {
+      case 'D':
+      case 'J':
+        // Move both pointers 64 bits.
+        dst_offset -= kPointerSize;
+        src_offset -= sizeof(JValue) / 2;
+        __ pushl(Address(rArgArray, src_offset));
+        dst_offset -= kPointerSize;
+        src_offset -= sizeof(JValue) / 2;
+        __ pushl(Address(rArgArray, src_offset));
+        break;
+      default:
+        // Move the source pointer sizeof(JValue) and the destination pointer 32 bits.
+        dst_offset -= kPointerSize;
+        src_offset -= sizeof(JValue);
+        __ pushl(Address(rArgArray, src_offset));
+        break;
+    }
+  }
+
+  // Backing space for receiver.
+  if (!is_static) {
+    __ pushl(Immediate(0));
+  }
+  // Push 0 as NULL Method* thereby terminating managed stack crawls.
+  __ pushl(Immediate(0));
+  if (!is_static) {
+    if (shorty_len > 1) {
+      // Receiver already in ECX, pass remaining 2 args in EDX and EBX.
+      __ movl(EDX, Address(rArgArray, 0));
+      if (shorty[1] == 'D' || shorty[1] == 'J') {
+        __ movl(EBX, Address(rArgArray, sizeof(JValue) / 2));
+      } else if (shorty_len > 2) {
+        __ movl(EBX, Address(rArgArray, sizeof(JValue)));
+      }
+    }
+  } else {
+    if (shorty_len > 1) {
+      // Pass remaining 3 args in ECX, EDX and EBX.
+      __ movl(ECX, Address(rArgArray, 0));
+      if (shorty[1] == 'D' || shorty[1] == 'J') {
+        __ movl(EDX, Address(rArgArray, sizeof(JValue) / 2));
+        if (shorty_len > 2) {
+           __ movl(EBX, Address(rArgArray, sizeof(JValue)));
+        }
+      } else if (shorty_len > 2) {
+        __ movl(EDX, Address(rArgArray, sizeof(JValue)));
+        if (shorty[2] == 'D' || shorty[2] == 'J') {
+          __ movl(EBX, Address(rArgArray, sizeof(JValue) + (sizeof(JValue) / 2)));
+        } else {
+          __ movl(EBX, Address(rArgArray, sizeof(JValue) + sizeof(JValue)));
+        }
+      }
+    }
+  }
+
+  __ call(Address(EAX, Method::GetCodeOffset()));  // Call code off of method
+
+  // Pop arguments up to EBX and the return address.
+  __ addl(ESP, Immediate(frame_size + pad_size - (2 * kPointerSize)));
+  // Restore EBX.
+  __ popl(EBX);
+  char ch = shorty[0];
+  if (ch != 'V') {
+    // Load the result JValue pointer.
+    __ movl(ECX, Address(ESP, 20));
+    switch (ch) {
+      case 'D':
+        __ movsd(Address(ECX, 0), XMM0);
+        break;
+      case 'F':
+        __ movss(Address(ECX, 0), XMM0);
+        break;
+      case 'J':
+        __ movl(Address(ECX, 0), EAX);
+        __ movl(Address(ECX, 4), EDX);
+        break;
+      default:
+        __ movl(Address(ECX, 0), EAX);
+        break;
+    }
+  }
+  __ ret();
+  // TODO: store native_entry in the stub table
+  std::vector<uint8_t> code(assembler->CodeSize());
+  MemoryRegion region(&code[0], code.size());
+  assembler->FinalizeInstructions(region);
+  return new CompiledInvokeStub(code);
+#undef __
+}
+
+CompiledInvokeStub* X86InvokeStubCompiler(art::Compiler& /*compiler*/,
+                                          bool is_static,
+                                          const char* shorty,
+                                          uint32_t shorty_len) {
+  return CreateInvokeStub(is_static, shorty, shorty_len);
+}
+
+} // anonymous namespace
+
+namespace art {
+namespace greenland {
+
+void InitializeX86InvokeStubCompiler() {
+  TargetRegistry::RegisterInvokeStubCompiler(kX86, X86InvokeStubCompiler);
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/x86/x86_lir.def b/src/greenland/x86/x86_lir.def
new file mode 100644
index 0000000..bf96b42
--- /dev/null
+++ b/src/greenland/x86/x86_lir.def
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "greenland/target_lir.def"
diff --git a/src/greenland/x86/x86_lir_emitter.cc b/src/greenland/x86/x86_lir_emitter.cc
new file mode 100644
index 0000000..7b56a9f
--- /dev/null
+++ b/src/greenland/x86/x86_lir_emitter.cc
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "x86_lir_emitter.h"
+
+namespace art {
+namespace greenland {
+
+X86LIREmitter::X86LIREmitter(const llvm::Function& func,
+                             const OatCompilationUnit& cunit,
+                             DexLang::Context& dex_lang_ctx,
+                             TargetLIRInfo& target_lir_info)
+    : TargetLIREmitter(func, cunit, dex_lang_ctx, target_lir_info) {
+  return;
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/x86/x86_lir_emitter.h b/src/greenland/x86/x86_lir_emitter.h
new file mode 100644
index 0000000..ab2d7c7
--- /dev/null
+++ b/src/greenland/x86/x86_lir_emitter.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_X86_LIR_EMITTER_H_
+#define ART_SRC_GREENLAND_X86_LIR_EMITTER_H_
+
+#include "greenland/target_lir_emitter.h"
+
+namespace art {
+namespace greenland {
+
+class TargetLIRInfo;
+
+class X86LIREmitter : public TargetLIREmitter {
+ private:
+
+
+ public:
+  X86LIREmitter(const llvm::Function& func,
+                const OatCompilationUnit& cunit,
+                DexLang::Context& dex_lang_ctx,
+                TargetLIRInfo& target_lir_info);
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_X86_LIR_EMITTER_H_
diff --git a/src/greenland/x86/x86_lir_info.cc b/src/greenland/x86/x86_lir_info.cc
new file mode 100644
index 0000000..2f29c97
--- /dev/null
+++ b/src/greenland/x86/x86_lir_info.cc
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "x86_lir_info.h"
+#include "x86_lir_opcodes.h"
+
+namespace {
+
+const art::greenland::LIRDesc X86LIR[] = {
+#define DEF_LIR_DESC(OPCODE, NUM_OPS) { art::greenland::x86::OPCODE, NUM_OPS },
+#include "x86_lir.def"
+#undef DEF_LIR_DESC
+};
+
+} // anonymous namespace
+
+namespace art {
+namespace greenland {
+
+X86LIRInfo::X86LIRInfo()
+    : TargetLIRInfo(X86LIR, sizeof(X86LIR) / sizeof(X86LIR[0])) {
+}
+
+} // namespace greenland
+} // namespace art
diff --git a/src/greenland/x86/x86_lir_info.h b/src/greenland/x86/x86_lir_info.h
new file mode 100644
index 0000000..92e4bae
--- /dev/null
+++ b/src/greenland/x86/x86_lir_info.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_X86_LIR_INFO_H_
+#define ART_SRC_GREENLAND_X86_LIR_INFO_H_
+
+#include "greenland/target_lir_info.h"
+
+namespace art {
+namespace greenland {
+
+class X86LIRInfo : public TargetLIRInfo {
+ private:
+
+ public:
+  X86LIRInfo();
+};
+
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_X86_LIR_INFO_H_
diff --git a/src/greenland/x86/x86_lir_opcodes.h b/src/greenland/x86/x86_lir_opcodes.h
new file mode 100644
index 0000000..487b609
--- /dev/null
+++ b/src/greenland/x86/x86_lir_opcodes.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GREENLAND_X86_LIR_OPCODES_H_
+#define ART_SRC_GREENLAND_X86_LIR_OPCODES_H_
+
+namespace art {
+namespace greenland {
+namespace x86 {
+
+enum {
+#define DEF_LIR_DESC(OPCODE, ...) OPCODE,
+#include "x86_lir.def"
+#undef DEF_LIR_DESC
+};
+
+} // namespace x86
+} // namespace greenland
+} // namespace art
+
+#endif // ART_SRC_GREENLAND_X86_LIR_OPCODES_H_
diff --git a/src/runtime.cc b/src/runtime.cc
index 226334e..d8beae8 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -101,7 +101,7 @@
 
   delete class_linker_;
   delete heap_;
-#if defined(ART_USE_LLVM_COMPILER)
+#if defined(ART_USE_LLVM_COMPILER) || defined(ART_USE_GREENLAND_COMPILER)
   verifier::MethodVerifier::DeleteInferredRegCategoryMaps();
 #endif
   verifier::MethodVerifier::DeleteGcMaps();
@@ -641,7 +641,7 @@
 
   verifier::MethodVerifier::InitGcMaps();
 
-#if defined(ART_USE_LLVM_COMPILER)
+#if defined(ART_USE_LLVM_COMPILER) || defined(ART_USE_GREENLAND_COMPILER)
   verifier::MethodVerifier::InitInferredRegCategoryMaps();
 #endif
 
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 81c755d..e772e67 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -38,6 +38,12 @@
 using namespace art::compiler_llvm;
 #endif
 
+#if defined(ART_USE_GREENLAND_COMPILER)
+#include "greenland/backend_types.h"
+#include "greenland/inferred_reg_category_map.h"
+using namespace art::greenland;
+#endif
+
 namespace art {
 namespace verifier {
 
@@ -946,7 +952,7 @@
 
   Compiler::MethodReference ref(dex_file_, method_idx_);
 
-#if !defined(ART_USE_LLVM_COMPILER)
+#if !defined(ART_USE_LLVM_COMPILER) && !defined(ART_USE_GREENLAND_COMPILER)
 
   /* Generate a register map and add it to the method. */
   UniquePtr<const std::vector<uint8_t> > map(GenerateGcMap());
@@ -964,8 +970,7 @@
     foo_method_->SetGcMap(&gc_map->at(0));
   }
 
-#else  //defined(ART_USE_LLVM_COMPILER)
-
+#else  // defined(ART_USE_LLVM_COMPILER) || defined(ART_USE_GREENLAND_COMPILER)
   /* Generate Inferred Register Category for LLVM-based Code Generator */
   const InferredRegCategoryMap* table = GenerateInferredRegCategoryMap();
   verifier::MethodVerifier::SetInferredRegCategoryMap(ref, *table);
@@ -3329,7 +3334,7 @@
   return (rejected_classes.find(ref) != rejected_classes.end());
 }
 
-#if defined(ART_USE_LLVM_COMPILER)
+#if defined(ART_USE_LLVM_COMPILER) || defined(ART_USE_GREENLAND_COMPILER)
 const InferredRegCategoryMap* MethodVerifier::GenerateInferredRegCategoryMap() {
   uint32_t insns_size = code_item_->insns_size_in_code_units_;
   uint16_t regs_size = code_item_->registers_size_;
diff --git a/src/verifier/method_verifier.h b/src/verifier/method_verifier.h
index 512e26f..639d736 100644
--- a/src/verifier/method_verifier.h
+++ b/src/verifier/method_verifier.h
@@ -45,6 +45,12 @@
 }  // namespace compiler_llvm
 #endif
 
+#if defined(ART_USE_GREENLAND_COMPILER)
+namespace greenland {
+  class InferredRegCategoryMap;
+}  // namespace greenland
+#endif
+
 namespace verifier {
 
 class MethodVerifier;
@@ -149,6 +155,11 @@
 
 // The verifier
 class MethodVerifier {
+#if defined(ART_USE_LLVM_COMPILER)
+  typedef compiler_llvm::InferredRegCategoryMap InferredRegCategoryMap;
+#elif defined(ART_USE_GREENLAND_COMPILER)
+  typedef greenland::InferredRegCategoryMap InferredRegCategoryMap;
+#endif
  public:
   /* Verify a class. Returns "true" on success. */
   static bool VerifyClass(const Class* klass, std::string& error);
@@ -185,8 +196,8 @@
   static void InitGcMaps();
   static void DeleteGcMaps();
 
-#if defined(ART_USE_LLVM_COMPILER)
-  static const compiler_llvm::InferredRegCategoryMap* GetInferredRegCategoryMap(Compiler::MethodReference ref);
+#if defined(ART_USE_LLVM_COMPILER) || defined(ART_USE_GREENLAND_COMPILER)
+  static const InferredRegCategoryMap* GetInferredRegCategoryMap(Compiler::MethodReference ref);
   static void InitInferredRegCategoryMaps();
   static void DeleteInferredRegCategoryMaps();
 #endif
@@ -530,12 +541,12 @@
   // Get a type representing the declaring class of the method.
   const RegType& GetDeclaringClass();
 
-#if defined(ART_USE_LLVM_COMPILER)
+#if defined(ART_USE_LLVM_COMPILER) || defined(ART_USE_GREENLAND_COMPILER)
   /*
    * Generate the inferred register category for LLVM-based code generator.
    * Returns a pointer to a two-dimension Class array, or NULL on failure.
    */
-  const compiler_llvm::InferredRegCategoryMap* GenerateInferredRegCategoryMap();
+  const InferredRegCategoryMap* GenerateInferredRegCategoryMap();
 #endif
 
   /*
@@ -560,14 +571,14 @@
   static GcMapTable* gc_maps_;
   static void SetGcMap(Compiler::MethodReference ref, const std::vector<uint8_t>& gc_map);
 
-#if defined(ART_USE_LLVM_COMPILER)
+#if defined(ART_USE_LLVM_COMPILER) || defined(ART_USE_GREENLAND_COMPILER)
   // All the inferred register category maps that the verifier has created
   typedef SafeMap<const Compiler::MethodReference,
-                  const compiler_llvm::InferredRegCategoryMap*> InferredRegCategoryMapTable;
+                  const InferredRegCategoryMap*> InferredRegCategoryMapTable;
   static Mutex* inferred_reg_category_maps_lock_;
   static InferredRegCategoryMapTable* inferred_reg_category_maps_;
   static void SetInferredRegCategoryMap(Compiler::MethodReference ref,
-                                        const compiler_llvm::InferredRegCategoryMap& m);
+                                        const InferredRegCategoryMap& m);
 #endif
 
   static void AddRejectedClass(Compiler::ClassReference ref);