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..04eec5e
--- /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 ®istry = *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);