Implement runtime support inlining.
Change-Id: I8608b246a4dfde9959b5b86872f65dfa61646c84
diff --git a/src/compiler_llvm/compilation_unit.cc b/src/compiler_llvm/compilation_unit.cc
index b3a9c71..fde023c 100644
--- a/src/compiler_llvm/compilation_unit.cc
+++ b/src/compiler_llvm/compilation_unit.cc
@@ -20,6 +20,9 @@
#include "ir_builder.h"
#include "logging.h"
+#include "runtime_support_builder_arm.h"
+#include "runtime_support_builder_x86.h"
+
#include <llvm/ADT/OwningPtr.h>
#include <llvm/ADT/StringSet.h>
#include <llvm/ADT/Triple.h>
@@ -70,6 +73,24 @@
// Create IRBuilder
irb_.reset(new IRBuilder(*context_, *module_));
+
+ // We always need a switch case, so just use a normal function.
+ switch(insn_set_) {
+ default:
+ runtime_support_.reset(new RuntimeSupportBuilder(*context_, *module_, *irb_));
+ break;
+ case kArm:
+ case kThumb2:
+ runtime_support_.reset(new RuntimeSupportBuilderARM(*context_, *module_, *irb_));
+ break;
+ case kX86:
+ runtime_support_.reset(new RuntimeSupportBuilderX86(*context_, *module_, *irb_));
+ break;
+ }
+
+ runtime_support_->OptimizeRuntimeSupport();
+
+ irb_->SetRuntimeSupport(runtime_support_.get());
}
diff --git a/src/compiler_llvm/compilation_unit.h b/src/compiler_llvm/compilation_unit.h
index 1db54fc..4b33ece 100644
--- a/src/compiler_llvm/compilation_unit.h
+++ b/src/compiler_llvm/compilation_unit.h
@@ -21,6 +21,8 @@
#include "globals.h"
#include "instruction_set.h"
#include "logging.h"
+#include "runtime_support_builder.h"
+#include "runtime_support_func.h"
#include <UniquePtr.h>
#include <string>
@@ -100,6 +102,7 @@
UniquePtr<llvm::LLVMContext> context_;
UniquePtr<IRBuilder> irb_;
+ UniquePtr<RuntimeSupportBuilder> runtime_support_;
llvm::Module* module_;
std::string elf_image_;
diff --git a/src/compiler_llvm/compiler_llvm.cc b/src/compiler_llvm/compiler_llvm.cc
index f9af139..baa6b2f 100644
--- a/src/compiler_llvm/compiler_llvm.cc
+++ b/src/compiler_llvm/compiler_llvm.cc
@@ -42,6 +42,8 @@
extern bool TimePassesIsEnabled;
}
+extern llvm::cl::opt<bool> ReserveR9;
+// ReserveR9 is defined in llvm/lib/Target/ARM/ARMSubtarget.cpp
extern llvm::cl::opt<bool> EnableARMLongCalls;
// NOTE: Although EnableARMLongCalls is defined in llvm/lib/Target/ARM/
// ARMISelLowering.cpp, however, it is not in the llvm namespace.
@@ -55,6 +57,9 @@
// NOTE: Uncomment following line to show the time consumption of LLVM passes
//llvm::TimePassesIsEnabled = true;
+ // Enable -arm-reserve-r9
+ ReserveR9 = true;
+
// Initialize LLVM target, MC subsystem, asm printer, and asm parser
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
diff --git a/src/compiler_llvm/ir_builder.cc b/src/compiler_llvm/ir_builder.cc
index 1a27d02..4afb8bc 100644
--- a/src/compiler_llvm/ir_builder.cc
+++ b/src/compiler_llvm/ir_builder.cc
@@ -15,7 +15,6 @@
*/
#include "ir_builder.h"
-#include "runtime_support_func.h"
#include "stringprintf.h"
#include <llvm/Module.h>
@@ -44,41 +43,7 @@
art_frame_type_ = module.getTypeByName("ShadowFrame");
CHECK(art_frame_type_ != NULL);
- // Load the runtime support function declaration from module
- InitRuntimeSupportFuncDecl();
-}
-
-
-//----------------------------------------------------------------------------
-// Runtime Helper Function
-//----------------------------------------------------------------------------
-
-void IRBuilder::InitRuntimeSupportFuncDecl() {
- using namespace runtime_support;
-
-#define GET_RUNTIME_SUPPORT_FUNC_DECL(ID, NAME) \
- do { \
- llvm::Function* fn = module_->getFunction(#NAME); \
- DCHECK_NE(fn, (void*)NULL) << "Function not found: " << #NAME; \
- runtime_support_func_decls_[ID] = fn; \
- } while (0);
-
-#include "runtime_support_func_list.h"
- RUNTIME_SUPPORT_FUNC_LIST(GET_RUNTIME_SUPPORT_FUNC_DECL)
-#undef RUNTIME_SUPPORT_FUNC_LIST
-#undef GET_RUNTIME_SUPPORT_FUNC_DECL
-}
-
-
-llvm::Function* IRBuilder::GetRuntime(runtime_support::RuntimeId rt) const {
- using namespace runtime_support;
-
- if (rt >= 0 && rt < MAX_ID) {
- return runtime_support_func_decls_[rt];
- } else {
- LOG(ERROR) << "Unknown runtime function id: " << rt;
- return NULL;
- }
+ runtime_support_ = NULL;
}
diff --git a/src/compiler_llvm/ir_builder.h b/src/compiler_llvm/ir_builder.h
index d199b76..9c8e229 100644
--- a/src/compiler_llvm/ir_builder.h
+++ b/src/compiler_llvm/ir_builder.h
@@ -18,6 +18,7 @@
#define ART_SRC_COMPILER_LLVM_IR_BUILDER_H_
#include "backend_types.h"
+#include "runtime_support_builder.h"
#include "runtime_support_func.h"
#include <llvm/Constants.h>
@@ -114,7 +115,17 @@
// Runtime Helper Function
//--------------------------------------------------------------------------
- llvm::Function* GetRuntime(runtime_support::RuntimeId rt) const;
+ llvm::Function* GetRuntime(runtime_support::RuntimeId rt) {
+ return runtime_support_->GetRuntimeSupportFunction(rt);
+ }
+
+ void SetRuntimeSupport(RuntimeSupportBuilder* runtime_support) {
+ // Can only set once. We can't do this on constructor, because RuntimeSupportBuilder needs
+ // IRBuilder.
+ if (runtime_support_ == NULL && runtime_support != NULL) {
+ runtime_support_ = runtime_support;
+ }
+ }
//--------------------------------------------------------------------------
@@ -282,13 +293,6 @@
private:
//--------------------------------------------------------------------------
- // Runtime Helper Function (Private)
- //--------------------------------------------------------------------------
-
- void InitRuntimeSupportFuncDecl();
-
-
- //--------------------------------------------------------------------------
// Type Helper Function (Private)
//--------------------------------------------------------------------------
@@ -306,7 +310,7 @@
llvm::StructType* art_frame_type_;
- llvm::Function* runtime_support_func_decls_[runtime_support::MAX_ID];
+ RuntimeSupportBuilder* runtime_support_;
};
diff --git a/src/compiler_llvm/runtime_support_builder.cc b/src/compiler_llvm/runtime_support_builder.cc
new file mode 100644
index 0000000..4183df6
--- /dev/null
+++ b/src/compiler_llvm/runtime_support_builder.cc
@@ -0,0 +1,168 @@
+/*
+ * 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 "runtime_support_builder.h"
+
+#include "ir_builder.h"
+#include "shadow_frame.h"
+#include "thread.h"
+
+#include <llvm/DerivedTypes.h>
+#include <llvm/Function.h>
+#include <llvm/Module.h>
+#include <llvm/Type.h>
+
+using namespace llvm;
+
+namespace art {
+namespace compiler_llvm {
+
+using namespace runtime_support;
+
+
+RuntimeSupportBuilder::RuntimeSupportBuilder(llvm::LLVMContext& context,
+ llvm::Module& module,
+ IRBuilder& irb)
+ : context_(context), module_(module), irb_(irb)
+{
+#define GET_RUNTIME_SUPPORT_FUNC_DECL(ID, NAME) \
+ do { \
+ llvm::Function* fn = module_.getFunction(#NAME); \
+ DCHECK_NE(fn, (void*)NULL) << "Function not found: " << #NAME; \
+ runtime_support_func_decls_[ID] = fn; \
+ } while (0);
+
+#include "runtime_support_func_list.h"
+ RUNTIME_SUPPORT_FUNC_LIST(GET_RUNTIME_SUPPORT_FUNC_DECL)
+#undef RUNTIME_SUPPORT_FUNC_LIST
+#undef GET_RUNTIME_SUPPORT_FUNC_DECL
+}
+
+void RuntimeSupportBuilder::MakeFunctionInline(llvm::Function* func) {
+ func->setLinkage(GlobalValue::LinkOnceODRLinkage);
+
+ SmallVector<AttributeWithIndex, 4> Attrs;
+ AttributeWithIndex PAWI;
+ PAWI.Index = ~0U;
+ PAWI.Attrs = Attribute::None | Attribute::NoUnwind | Attribute::AlwaysInline;
+ Attrs.push_back(PAWI);
+ AttrListPtr func_PAL = AttrListPtr::get(Attrs.begin(), Attrs.end());
+
+ func->setAttributes(func_PAL);
+}
+
+void RuntimeSupportBuilder::OverrideRuntimeSupportFunction(RuntimeId id, llvm::Function* function) {
+ // TODO: Check function prototype.
+ if (id >= 0 && id < MAX_ID) {
+ runtime_support_func_decls_[id] = function;
+ target_runtime_support_func_[id] = true;
+ } else {
+ LOG(ERROR) << "Unknown runtime function id: " << id;
+ }
+}
+
+void RuntimeSupportBuilder::OptimizeRuntimeSupport() {
+ TargetOptimizeRuntimeSupport();
+
+ if (!target_runtime_support_func_[PushShadowFrame]) {
+ Function* func = GetRuntimeSupportFunction(PushShadowFrame);
+ MakeFunctionInline(func);
+ BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
+ irb_.SetInsertPoint(basic_block);
+
+ Function* get_thread = GetRuntimeSupportFunction(GetCurrentThread);
+ Value* thread = irb_.CreateCall(get_thread);
+ Value* new_shadow_frame = func->arg_begin();
+ Value* old_shadow_frame = irb_.LoadFromObjectOffset(thread,
+ Thread::TopShadowFrameOffset().Int32Value(),
+ irb_.getJObjectTy());
+ irb_.StoreToObjectOffset(new_shadow_frame,
+ ShadowFrame::LinkOffset(),
+ old_shadow_frame);
+ irb_.StoreToObjectOffset(thread,
+ Thread::TopShadowFrameOffset().Int32Value(),
+ new_shadow_frame);
+ irb_.CreateRetVoid();
+ }
+
+ if (!target_runtime_support_func_[PopShadowFrame]) {
+ Function* func = GetRuntimeSupportFunction(PopShadowFrame);
+ MakeFunctionInline(func);
+ BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
+ irb_.SetInsertPoint(basic_block);
+
+ Function* get_thread = GetRuntimeSupportFunction(GetCurrentThread);
+ Value* thread = irb_.CreateCall(get_thread);
+ Value* new_shadow_frame = irb_.LoadFromObjectOffset(thread,
+ Thread::TopShadowFrameOffset().Int32Value(),
+ irb_.getJObjectTy());
+ Value* old_shadow_frame = irb_.LoadFromObjectOffset(new_shadow_frame,
+ ShadowFrame::LinkOffset(),
+ irb_.getJObjectTy());
+ irb_.StoreToObjectOffset(thread,
+ Thread::TopShadowFrameOffset().Int32Value(),
+ old_shadow_frame);
+ irb_.CreateRetVoid();
+ }
+
+ if (!target_runtime_support_func_[IsExceptionPending]) {
+ Function* func = GetRuntimeSupportFunction(IsExceptionPending);
+ MakeFunctionInline(func);
+ BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
+ irb_.SetInsertPoint(basic_block);
+
+ Function* get_thread = GetRuntimeSupportFunction(GetCurrentThread);
+ Value* thread = irb_.CreateCall(get_thread);
+ Value* exception = irb_.LoadFromObjectOffset(thread,
+ Thread::ExceptionOffset().Int32Value(),
+ irb_.getJObjectTy());
+ Value* is_exception_not_null = irb_.CreateICmpNE(exception, irb_.getJNull());
+ irb_.CreateRet(is_exception_not_null);
+ }
+
+ if (!target_runtime_support_func_[TestSuspend]) {
+ Function* slow_func = GetRuntimeSupportFunction(TestSuspend);
+
+ Function* func = Function::Create(slow_func->getFunctionType(),
+ GlobalValue::LinkOnceODRLinkage,
+ "test_suspend_fast",
+ &module_);
+ MakeFunctionInline(func);
+ BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
+ irb_.SetInsertPoint(basic_block);
+
+ Function* get_thread = GetRuntimeSupportFunction(GetCurrentThread);
+ Value* thread = irb_.CreateCall(get_thread);
+ Value* suspend_count = irb_.LoadFromObjectOffset(thread,
+ Thread::SuspendCountOffset().Int32Value(),
+ irb_.getJIntTy());
+ Value* is_suspend = irb_.CreateICmpNE(suspend_count, irb_.getJInt(0));
+
+ BasicBlock* basic_block_suspend = BasicBlock::Create(context_, "suspend", func);
+ BasicBlock* basic_block_else = BasicBlock::Create(context_, "else", func);
+ irb_.CreateCondBr(is_suspend, basic_block_suspend, basic_block_else);
+ irb_.SetInsertPoint(basic_block_suspend);
+ irb_.CreateCall(slow_func);
+ irb_.CreateBr(basic_block_else);
+ irb_.SetInsertPoint(basic_block_else);
+ irb_.CreateRetVoid();
+
+ OverrideRuntimeSupportFunction(TestSuspend, func);
+ }
+}
+
+} // namespace compiler_llvm
+} // namespace art
diff --git a/src/compiler_llvm/runtime_support_builder.h b/src/compiler_llvm/runtime_support_builder.h
new file mode 100644
index 0000000..422285c
--- /dev/null
+++ b/src/compiler_llvm/runtime_support_builder.h
@@ -0,0 +1,78 @@
+/*
+ * 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_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_H_
+#define ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_H_
+
+#include "logging.h"
+#include "runtime_support_func.h"
+
+namespace llvm {
+ class LLVMContext;
+ class Module;
+ class Function;
+}
+
+namespace art {
+namespace compiler_llvm {
+
+class IRBuilder;
+
+
+class RuntimeSupportBuilder {
+ public:
+ RuntimeSupportBuilder(llvm::LLVMContext& context, llvm::Module& module, IRBuilder& irb);
+
+ llvm::Function* GetRuntimeSupportFunction(runtime_support::RuntimeId id) {
+ if (id >= 0 && id < runtime_support::MAX_ID) {
+ return runtime_support_func_decls_[id];
+ } else {
+ LOG(ERROR) << "Unknown runtime function id: " << id;
+ return NULL;
+ }
+ }
+
+ void OptimizeRuntimeSupport();
+
+ virtual ~RuntimeSupportBuilder() {}
+
+ protected:
+ // Mark a function as inline function.
+ // You should implement the function, if mark as inline.
+ void MakeFunctionInline(llvm::Function* function);
+
+ void OverrideRuntimeSupportFunction(runtime_support::RuntimeId id, llvm::Function* function);
+
+ private:
+ // Target can override this function to make some runtime support more efficient.
+ virtual void TargetOptimizeRuntimeSupport() {}
+
+
+ protected:
+ llvm::LLVMContext& context_;
+ llvm::Module& module_;
+ IRBuilder& irb_;
+
+ private:
+ llvm::Function* runtime_support_func_decls_[runtime_support::MAX_ID];
+ bool target_runtime_support_func_[runtime_support::MAX_ID];
+};
+
+
+} // namespace compiler_llvm
+} // namespace art
+
+#endif // ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_H_
diff --git a/src/compiler_llvm/runtime_support_builder_arm.cc b/src/compiler_llvm/runtime_support_builder_arm.cc
new file mode 100644
index 0000000..ab33967
--- /dev/null
+++ b/src/compiler_llvm/runtime_support_builder_arm.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 "runtime_support_builder_arm.h"
+
+#include "ir_builder.h"
+#include "thread.h"
+
+#include <llvm/DerivedTypes.h>
+#include <llvm/Function.h>
+#include <llvm/InlineAsm.h>
+#include <llvm/Module.h>
+#include <llvm/Type.h>
+
+#include <vector>
+
+using namespace llvm;
+
+namespace art {
+namespace compiler_llvm {
+
+using namespace runtime_support;
+
+
+void RuntimeSupportBuilderARM::TargetOptimizeRuntimeSupport() {
+ {
+ Function* func = GetRuntimeSupportFunction(GetCurrentThread);
+ MakeFunctionInline(func);
+ BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
+ irb_.SetInsertPoint(basic_block);
+
+ InlineAsm* get_r9 = InlineAsm::get(func->getFunctionType(), "mov $0, r9", "=r", false);
+ Value* r9 = irb_.CreateCall(get_r9);
+ irb_.CreateRet(r9);
+ }
+
+ {
+ Function* func = GetRuntimeSupportFunction(SetCurrentThread);
+ MakeFunctionInline(func);
+ BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
+ irb_.SetInsertPoint(basic_block);
+
+ InlineAsm* set_r9 = InlineAsm::get(func->getFunctionType(), "mov r9, $0", "r", true);
+ Value* thread = func->arg_begin();
+ irb_.CreateCall(set_r9, thread);
+ irb_.CreateRetVoid();
+ }
+}
+
+
+} // namespace compiler_llvm
+} // namespace art
diff --git a/src/compiler_llvm/runtime_support_builder_arm.h b/src/compiler_llvm/runtime_support_builder_arm.h
new file mode 100644
index 0000000..e179366
--- /dev/null
+++ b/src/compiler_llvm/runtime_support_builder_arm.h
@@ -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.
+ */
+
+#ifndef ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_ARM_H_
+#define ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_ARM_H_
+
+#include "runtime_support_builder.h"
+
+namespace art {
+namespace compiler_llvm {
+
+class RuntimeSupportBuilderARM : public RuntimeSupportBuilder {
+ public:
+ RuntimeSupportBuilderARM(llvm::LLVMContext& context, llvm::Module& module, IRBuilder& irb)
+ : RuntimeSupportBuilder(context, module, irb) {}
+ private:
+ virtual void TargetOptimizeRuntimeSupport();
+};
+
+} // namespace compiler_llvm
+} // namespace art
+
+#endif // ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_ARM_H_
diff --git a/src/compiler_llvm/runtime_support_builder_x86.cc b/src/compiler_llvm/runtime_support_builder_x86.cc
new file mode 100644
index 0000000..c381874
--- /dev/null
+++ b/src/compiler_llvm/runtime_support_builder_x86.cc
@@ -0,0 +1,66 @@
+/*
+ * 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 "runtime_support_builder_x86.h"
+
+#include "ir_builder.h"
+#include "thread.h"
+
+#include <llvm/DerivedTypes.h>
+#include <llvm/Function.h>
+#include <llvm/InlineAsm.h>
+#include <llvm/Module.h>
+#include <llvm/Type.h>
+
+#include <vector>
+
+using namespace llvm;
+
+namespace art {
+namespace compiler_llvm {
+
+using namespace runtime_support;
+
+
+void RuntimeSupportBuilderX86::TargetOptimizeRuntimeSupport() {
+ {
+ Function* func = GetRuntimeSupportFunction(GetCurrentThread);
+ MakeFunctionInline(func);
+ BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
+ irb_.SetInsertPoint(basic_block);
+
+ std::vector<Type*> func_ty_args;
+ func_ty_args.push_back(irb_.getPtrEquivIntTy());
+ FunctionType* func_ty = FunctionType::get(/*Result=*/irb_.getJObjectTy(),
+ /*Params=*/func_ty_args,
+ /*isVarArg=*/false);
+ InlineAsm* get_fp = InlineAsm::get(func_ty, "movl %fs:($1), $0", "=r,r", false);
+ Value* fp = irb_.CreateCall(get_fp, irb_.getPtrEquivInt(Thread::SelfOffset().Int32Value()));
+ irb_.CreateRet(fp);
+ }
+
+ {
+ Function* func = GetRuntimeSupportFunction(SetCurrentThread);
+ MakeFunctionInline(func);
+ BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
+ irb_.SetInsertPoint(basic_block);
+ irb_.CreateRetVoid();
+ }
+}
+
+
+} // namespace compiler_llvm
+} // namespace art
diff --git a/src/compiler_llvm/runtime_support_builder_x86.h b/src/compiler_llvm/runtime_support_builder_x86.h
new file mode 100644
index 0000000..37de81b
--- /dev/null
+++ b/src/compiler_llvm/runtime_support_builder_x86.h
@@ -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.
+ */
+
+#ifndef ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_X86_H_
+#define ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_X86_H_
+
+#include "runtime_support_builder.h"
+
+namespace art {
+namespace compiler_llvm {
+
+class RuntimeSupportBuilderX86 : public RuntimeSupportBuilder {
+ public:
+ RuntimeSupportBuilderX86(llvm::LLVMContext& context, llvm::Module& module, IRBuilder& irb)
+ : RuntimeSupportBuilder(context, module, irb) {}
+ private:
+ virtual void TargetOptimizeRuntimeSupport();
+};
+
+} // namespace compiler_llvm
+} // namespace art
+
+#endif // ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_X86_H_
diff --git a/src/compiler_llvm/runtime_support_func.h b/src/compiler_llvm/runtime_support_func.h
index 480b054..de3ed26 100644
--- a/src/compiler_llvm/runtime_support_func.h
+++ b/src/compiler_llvm/runtime_support_func.h
@@ -19,8 +19,8 @@
namespace art {
namespace compiler_llvm {
-
namespace runtime_support {
+
enum RuntimeId {
#define DEFINE_RUNTIME_SUPPORT_FUNC_ID(ID, NAME) ID,
#include "runtime_support_func_list.h"
@@ -30,8 +30,8 @@
MAX_ID
};
-}
+} // namespace runtime_support
} // namespace compiler_llvm
} // namespace art
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index 18e4842..c526847 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -31,6 +31,8 @@
#include <cstdarg>
#include <stdint.h>
+#include "asm_support.h"
+
namespace art {
//----------------------------------------------------------------------------
@@ -38,16 +40,23 @@
//----------------------------------------------------------------------------
Thread* art_get_current_thread_from_code() {
+#if defined(__i386__)
+ Thread* ptr;
+ asm volatile("movl %%fs:(%1), %0"
+ : "=r"(ptr) // output
+ : "r"(THREAD_SELF_OFFSET) // input
+ :); // clobber
+ return ptr;
+#else
return Thread::Current();
+#endif
}
void art_set_current_thread_from_code(void* thread_object_addr) {
- // TODO: LLVM IR generating something like "r9 = thread_object_addr"
- // UNIMPLEMENTED(WARNING);
}
void art_lock_object_from_code(Object* obj) {
- Thread* thread = Thread::Current();
+ Thread* thread = art_get_current_thread_from_code();
DCHECK(obj != NULL); // Assumed to have been checked before entry
obj->MonitorEnter(thread); // May block
DCHECK(thread->HoldsLock(obj));
@@ -56,24 +65,24 @@
}
void art_unlock_object_from_code(Object* obj) {
- Thread* thread = Thread::Current();
+ Thread* thread = art_get_current_thread_from_code();
DCHECK(obj != NULL); // Assumed to have been checked before entry
// MonitorExit may throw exception
obj->MonitorExit(thread);
}
void art_test_suspend_from_code() {
- Thread* thread = Thread::Current();
+ Thread* thread = art_get_current_thread_from_code();
Runtime::Current()->GetThreadList()->FullSuspendCheck(thread);
}
void art_push_shadow_frame_from_code(void* new_shadow_frame) {
- Thread* thread = Thread::Current();
+ Thread* thread = art_get_current_thread_from_code();
thread->PushShadowFrame(static_cast<ShadowFrame*>(new_shadow_frame));
}
void art_pop_shadow_frame_from_code() {
- Thread* thread = Thread::Current();
+ Thread* thread = art_get_current_thread_from_code();
thread->PopShadowFrame();
}
@@ -84,23 +93,23 @@
//----------------------------------------------------------------------------
bool art_is_exception_pending_from_code() {
- return Thread::Current()->IsExceptionPending();
+ return art_get_current_thread_from_code()->IsExceptionPending();
}
void art_throw_div_zero_from_code() {
- Thread* thread = Thread::Current();
+ Thread* thread = art_get_current_thread_from_code();
thread->ThrowNewException("Ljava/lang/ArithmeticException;",
"divide by zero");
}
void art_throw_array_bounds_from_code(int32_t length, int32_t index) {
- Thread* thread = Thread::Current();
+ Thread* thread = art_get_current_thread_from_code();
thread->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
"length=%d; index=%d", length, index);
}
void art_throw_no_such_method_from_code(int32_t method_idx) {
- Thread* thread = Thread::Current();
+ Thread* thread = art_get_current_thread_from_code();
// We need the calling method as context for the method_idx
Frame frame = thread->GetTopOfStack();
frame.Next();
@@ -113,7 +122,7 @@
}
void art_throw_null_pointer_exception_from_code(uint32_t dex_pc) {
- Thread* thread = Thread::Current();
+ Thread* thread = art_get_current_thread_from_code();
NthCallerVisitor visitor(0);
thread->WalkStack(&visitor);
Method* throw_method = visitor.caller;
@@ -121,7 +130,7 @@
}
void art_throw_stack_overflow_from_code() {
- Thread* thread = Thread::Current();
+ Thread* thread = art_get_current_thread_from_code();
if (Runtime::Current()->IsMethodTracingActive()) {
TraceMethodUnwindFromCode(thread);
}
@@ -134,7 +143,7 @@
}
void art_throw_exception_from_code(Object* exception) {
- Thread* thread = Thread::Current();
+ Thread* thread = art_get_current_thread_from_code();
if (exception == NULL) {
thread->ThrowNewException("Ljava/lang/NullPointerException;", "throw with null exception");
} else {
@@ -145,11 +154,11 @@
void art_throw_verification_error_from_code(Method* current_method,
int32_t kind,
int32_t ref) {
- ThrowVerificationError(Thread::Current(), current_method, kind, ref);
+ ThrowVerificationError(art_get_current_thread_from_code(), current_method, kind, ref);
}
int32_t art_find_catch_block_from_code(Method* current_method, int32_t dex_pc) {
- Thread* thread = Thread::Current();
+ Thread* thread = art_get_current_thread_from_code();
Class* exception_type = thread->GetException()->GetClass();
MethodHelper mh(current_method);
const DexFile::CodeItem* code_item = mh.GetCodeItem();
@@ -182,33 +191,33 @@
//----------------------------------------------------------------------------
Object* art_alloc_object_from_code(uint32_t type_idx, Method* referrer) {
- return AllocObjectFromCode(type_idx, referrer, Thread::Current(), false);
+ return AllocObjectFromCode(type_idx, referrer, art_get_current_thread_from_code(), false);
}
Object* art_alloc_object_from_code_with_access_check(uint32_t type_idx, Method* referrer) {
- return AllocObjectFromCode(type_idx, referrer, Thread::Current(), true);
+ return AllocObjectFromCode(type_idx, referrer, art_get_current_thread_from_code(), true);
}
Object* art_alloc_array_from_code(uint32_t type_idx, Method* referrer, uint32_t length) {
- return AllocArrayFromCode(type_idx, referrer, length, Thread::Current(), false);
+ return AllocArrayFromCode(type_idx, referrer, length, art_get_current_thread_from_code(), false);
}
Object* art_alloc_array_from_code_with_access_check(uint32_t type_idx,
Method* referrer,
uint32_t length) {
- return AllocArrayFromCode(type_idx, referrer, length, Thread::Current(), true);
+ return AllocArrayFromCode(type_idx, referrer, length, art_get_current_thread_from_code(), true);
}
Object* art_check_and_alloc_array_from_code(uint32_t type_idx,
Method* referrer,
uint32_t length) {
- return CheckAndAllocArrayFromCode(type_idx, referrer, length, Thread::Current(), false);
+ return CheckAndAllocArrayFromCode(type_idx, referrer, length, art_get_current_thread_from_code(), false);
}
Object* art_check_and_alloc_array_from_code_with_access_check(uint32_t type_idx,
Method* referrer,
uint32_t length) {
- return CheckAndAllocArrayFromCode(type_idx, referrer, length, Thread::Current(), true);
+ return CheckAndAllocArrayFromCode(type_idx, referrer, length, art_get_current_thread_from_code(), true);
}
static Method* FindMethodHelper(uint32_t method_idx, Object* this_object, Method* caller_method,
@@ -216,13 +225,13 @@
Method* method = FindMethodFast(method_idx, this_object, caller_method, access_check, type);
if (UNLIKELY(method == NULL)) {
method = FindMethodFromCode(method_idx, this_object, caller_method,
- Thread::Current(), access_check, type);
+ art_get_current_thread_from_code(), access_check, type);
if (UNLIKELY(method == NULL)) {
- CHECK(Thread::Current()->IsExceptionPending());
+ CHECK(art_get_current_thread_from_code()->IsExceptionPending());
return 0; // failure
}
}
- DCHECK(!Thread::Current()->IsExceptionPending());
+ DCHECK(!art_get_current_thread_from_code()->IsExceptionPending());
return method;
}
@@ -264,17 +273,17 @@
}
Object* art_initialize_static_storage_from_code(uint32_t type_idx, Method* referrer) {
- return ResolveVerifyAndClinit(type_idx, referrer, Thread::Current(), true, false);
+ return ResolveVerifyAndClinit(type_idx, referrer, art_get_current_thread_from_code(), true, false);
}
Object* art_initialize_type_from_code(uint32_t type_idx, Method* referrer) {
- return ResolveVerifyAndClinit(type_idx, referrer, Thread::Current(), false, false);
+ return ResolveVerifyAndClinit(type_idx, referrer, art_get_current_thread_from_code(), false, false);
}
Object* art_initialize_type_and_verify_access_from_code(uint32_t type_idx, Method* referrer) {
// Called when caller isn't guaranteed to have access to a type and the dex cache may be
// unpopulated
- return ResolveVerifyAndClinit(type_idx, referrer, Thread::Current(), false, true);
+ return ResolveVerifyAndClinit(type_idx, referrer, art_get_current_thread_from_code(), false, true);
}
Object* art_resolve_string_from_code(Method* referrer, uint32_t string_idx) {
@@ -287,7 +296,7 @@
field->Set32(NULL, new_value);
return 0;
}
- field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
true, true, true, sizeof(uint32_t));
if (LIKELY(field != NULL)) {
field->Set32(NULL, new_value);
@@ -302,7 +311,7 @@
field->Set64(NULL, new_value);
return 0;
}
- field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
true, true, true, sizeof(uint64_t));
if (LIKELY(field != NULL)) {
field->Set64(NULL, new_value);
@@ -317,7 +326,7 @@
field->SetObj(NULL, new_value);
return 0;
}
- field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
true, false, true, sizeof(Object*));
if (LIKELY(field != NULL)) {
field->SetObj(NULL, new_value);
@@ -331,7 +340,7 @@
if (LIKELY(field != NULL)) {
return field->Get32(NULL);
}
- field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
true, true, false, sizeof(uint32_t));
if (LIKELY(field != NULL)) {
return field->Get32(NULL);
@@ -344,7 +353,7 @@
if (LIKELY(field != NULL)) {
return field->Get64(NULL);
}
- field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
true, true, false, sizeof(uint64_t));
if (LIKELY(field != NULL)) {
return field->Get64(NULL);
@@ -357,7 +366,7 @@
if (LIKELY(field != NULL)) {
return field->GetObj(NULL);
}
- field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
true, false, false, sizeof(Object*));
if (LIKELY(field != NULL)) {
return field->GetObj(NULL);
@@ -372,7 +381,7 @@
field->Set32(obj, new_value);
return 0;
}
- field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
false, true, true, sizeof(uint32_t));
if (LIKELY(field != NULL)) {
field->Set32(obj, new_value);
@@ -388,7 +397,7 @@
field->Set64(obj, new_value);
return 0;
}
- field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
false, true, true, sizeof(uint64_t));
if (LIKELY(field != NULL)) {
field->Set64(obj, new_value);
@@ -404,7 +413,7 @@
field->SetObj(obj, new_value);
return 0;
}
- field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
false, false, true, sizeof(Object*));
if (LIKELY(field != NULL)) {
field->SetObj(obj, new_value);
@@ -418,7 +427,7 @@
if (LIKELY(field != NULL)) {
return field->Get32(obj);
}
- field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
false, true, false, sizeof(uint32_t));
if (LIKELY(field != NULL)) {
return field->Get32(obj);
@@ -431,7 +440,7 @@
if (LIKELY(field != NULL)) {
return field->Get64(obj);
}
- field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
false, true, false, sizeof(uint64_t));
if (LIKELY(field != NULL)) {
return field->Get64(obj);
@@ -444,7 +453,7 @@
if (LIKELY(field != NULL)) {
return field->GetObj(obj);
}
- field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
false, false, false, sizeof(Object*));
if (LIKELY(field != NULL)) {
return field->GetObj(obj);
@@ -473,10 +482,11 @@
DCHECK(dest_type->IsClass()) << PrettyClass(dest_type);
DCHECK(src_type->IsClass()) << PrettyClass(src_type);
if (UNLIKELY(!dest_type->IsAssignableFrom(src_type))) {
- Thread::Current()->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
- "%s cannot be cast to %s",
- PrettyDescriptor(dest_type).c_str(),
- PrettyDescriptor(src_type).c_str());
+ Thread* thread = art_get_current_thread_from_code();
+ thread->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
+ "%s cannot be cast to %s",
+ PrettyDescriptor(dest_type).c_str(),
+ PrettyDescriptor(src_type).c_str());
}
}
@@ -490,10 +500,11 @@
Class* component_type = array_class->GetComponentType();
Class* element_class = element->GetClass();
if (UNLIKELY(!component_type->IsAssignableFrom(element_class))) {
- Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;",
- "%s cannot be stored in an array of type %s",
- PrettyDescriptor(element_class).c_str(),
- PrettyDescriptor(array_class).c_str());
+ Thread* thread = art_get_current_thread_from_code();
+ thread->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;",
+ "%s cannot be stored in an array of type %s",
+ PrettyDescriptor(element_class).c_str(),
+ PrettyDescriptor(array_class).c_str());
}
return;
}
@@ -566,7 +577,7 @@
// Resolve method.
ClassLinker* linker = Runtime::Current()->GetClassLinker();
called = linker->ResolveMethod(dex_method_idx, caller, !is_virtual);
- if (UNLIKELY(Thread::Current()->IsExceptionPending())) {
+ if (UNLIKELY(art_get_current_thread_from_code()->IsExceptionPending())) {
return NULL;
}
if (LIKELY(called->IsDirect() == !is_virtual)) {
@@ -575,10 +586,11 @@
linker->EnsureInitialized(called_class, true, true);
return called;
} else {
+ Thread* thread = art_get_current_thread_from_code();
// Direct method has been made virtual
- Thread::Current()->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
- "Expected direct method but found virtual: %s",
- PrettyMethod(called, true).c_str());
+ thread->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
+ "Expected direct method but found virtual: %s",
+ PrettyMethod(called, true).c_str());
return NULL;
}
}
@@ -609,7 +621,7 @@
} else if (called_class->IsInitializing()) {
return linker->GetOatCodeFor(called);
} else {
- DCHECK(Thread::Current()->IsExceptionPending());
+ DCHECK(art_get_current_thread_from_code()->IsExceptionPending());
DCHECK(called_class->IsErroneous());
return NULL;
}
@@ -617,8 +629,9 @@
// 2. The code address is AbstractMethodErrorStub. -> AbstractMethodErrorStub
if (UNLIKELY(code == runtime->GetAbstractMethodErrorStubArray()->GetData())) {
- Thread::Current()->ThrowNewExceptionF("Ljava/lang/AbstractMethodError;",
- "abstract method \"%s\"", PrettyMethod(called).c_str());
+ art_get_current_thread_from_code()->ThrowNewExceptionF("Ljava/lang/AbstractMethodError;",
+ "abstract method \"%s\"",
+ PrettyMethod(called).c_str());
return NULL;
}
@@ -638,7 +651,7 @@
va_start(ap, proxy_method);
Object* receiver = va_arg(ap, Object*);
- Thread* thread = Thread::Current();
+ Thread* thread = art_get_current_thread_from_code();
MethodHelper proxy_mh(proxy_method);
const size_t num_params = proxy_mh.NumArgs();
diff --git a/src/shadow_frame.h b/src/shadow_frame.h
index a12abc8..261875e 100644
--- a/src/shadow_frame.h
+++ b/src/shadow_frame.h
@@ -23,6 +23,7 @@
namespace art {
class Object;
+class Method;
class ShadowFrame {
public:
diff --git a/src/thread.h b/src/thread.h
index 2cb59d5..4f43473 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -433,6 +433,10 @@
void PushShadowFrame(ShadowFrame* frame);
ShadowFrame* PopShadowFrame();
+ static ThreadOffset TopShadowFrameOffset() {
+ return ThreadOffset(OFFSETOF_MEMBER(Thread, top_shadow_frame_));
+ }
+
void PushSirt(StackIndirectReferenceTable* sirt);
StackIndirectReferenceTable* PopSirt();