Stackmaps are used for OSR exits, which is a custom kind of unwinding. Hence, they

should not be marked nounwind.

Marking them nounwind caused crashes in the WebKit FTL JIT, because if we enable 
sufficient optimizations, LLVM starts eliding compact_unwind sections (or any unwind 
data for that matter), making deoptimization via stackmaps impossible.

This changes the stackmap intrinsic to be may-throw, adds a test for exactly the 
sympton that WebKit saw, and fixes TableGen to handle un-attributed intrinsics.

Thanks to atrick and philipreames for reviewing this.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@201826 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Filip Pizlo 2014-02-20 23:57:31 +00:00
parent 0aabe661a4
commit 23ffb3ea10
5 changed files with 95 additions and 2 deletions

View File

@ -458,7 +458,8 @@ def int_invariant_end : Intrinsic<[],
//===------------------------ Stackmap Intrinsics -------------------------===// //===------------------------ Stackmap Intrinsics -------------------------===//
// //
def int_experimental_stackmap : Intrinsic<[], def int_experimental_stackmap : Intrinsic<[],
[llvm_i64_ty, llvm_i32_ty, llvm_vararg_ty]>; [llvm_i64_ty, llvm_i32_ty, llvm_vararg_ty],
[Throws]>;
def int_experimental_patchpoint_void : Intrinsic<[], def int_experimental_patchpoint_void : Intrinsic<[],
[llvm_i64_ty, llvm_i32_ty, [llvm_i64_ty, llvm_i32_ty,
llvm_ptr_ty, llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty,

View File

@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS
Analysis Analysis
Core Core
ExecutionEngine ExecutionEngine
IPO
JIT JIT
MCJIT MCJIT
ScalarOpts ScalarOpts

View File

@ -18,6 +18,7 @@
#include "llvm-c/ExecutionEngine.h" #include "llvm-c/ExecutionEngine.h"
#include "llvm-c/Target.h" #include "llvm-c/Target.h"
#include "llvm-c/Transforms/Scalar.h" #include "llvm-c/Transforms/Scalar.h"
#include "llvm-c/Transforms/PassManagerBuilder.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/Support/Host.h" #include "llvm/Support/Host.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
@ -26,6 +27,7 @@
using namespace llvm; using namespace llvm;
static bool didCallAllocateCodeSection; static bool didCallAllocateCodeSection;
static bool didAllocateCompactUnwindSection;
static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size, static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size,
unsigned alignment, unsigned alignment,
@ -41,6 +43,8 @@ static uint8_t *roundTripAllocateDataSection(void *object, uintptr_t size,
unsigned sectionID, unsigned sectionID,
const char *sectionName, const char *sectionName,
LLVMBool isReadOnly) { LLVMBool isReadOnly) {
if (!strcmp(sectionName, "__compact_unwind"))
didAllocateCompactUnwindSection = true;
return static_cast<SectionMemoryManager*>(object)->allocateDataSection( return static_cast<SectionMemoryManager*>(object)->allocateDataSection(
size, alignment, sectionID, sectionName, isReadOnly); size, alignment, sectionID, sectionName, isReadOnly);
} }
@ -135,6 +139,7 @@ protected:
virtual void SetUp() { virtual void SetUp() {
didCallAllocateCodeSection = false; didCallAllocateCodeSection = false;
didAllocateCompactUnwindSection = false;
Module = 0; Module = 0;
Function = 0; Function = 0;
Engine = 0; Engine = 0;
@ -168,6 +173,36 @@ protected:
LLVMDisposeBuilder(builder); LLVMDisposeBuilder(builder);
} }
void buildFunctionThatUsesStackmap() {
Module = LLVMModuleCreateWithName("simple_module");
LLVMSetTarget(Module, HostTriple.c_str());
LLVMTypeRef stackmapParamTypes[] = { LLVMInt64Type(), LLVMInt32Type() };
LLVMValueRef stackmap = LLVMAddFunction(
Module, "llvm.experimental.stackmap",
LLVMFunctionType(LLVMVoidType(), stackmapParamTypes, 2, 1));
LLVMSetLinkage(stackmap, LLVMExternalLinkage);
Function = LLVMAddFunction(
Module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
LLVMBuilderRef builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(builder, entry);
LLVMValueRef stackmapArgs[] = {
LLVMConstInt(LLVMInt64Type(), 0, 0), LLVMConstInt(LLVMInt32Type(), 5, 0),
LLVMConstInt(LLVMInt32Type(), 42, 0)
};
LLVMBuildCall(builder, stackmap, stackmapArgs, 3, "");
LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
LLVMDisposeMessage(Error);
LLVMDisposeBuilder(builder);
}
void buildModuleWithCodeAndData() { void buildModuleWithCodeAndData() {
Module = LLVMModuleCreateWithName("simple_module"); Module = LLVMModuleCreateWithName("simple_module");
@ -248,6 +283,38 @@ protected:
LLVMDisposePassManager(pass); LLVMDisposePassManager(pass);
} }
void buildAndRunOptPasses() {
LLVMPassManagerBuilderRef passBuilder;
passBuilder = LLVMPassManagerBuilderCreate();
LLVMPassManagerBuilderSetOptLevel(passBuilder, 2);
LLVMPassManagerBuilderSetSizeLevel(passBuilder, 0);
LLVMPassManagerRef functionPasses =
LLVMCreateFunctionPassManagerForModule(Module);
LLVMPassManagerRef modulePasses =
LLVMCreatePassManager();
LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), modulePasses);
LLVMPassManagerBuilderPopulateFunctionPassManager(passBuilder,
functionPasses);
LLVMPassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses);
LLVMPassManagerBuilderDispose(passBuilder);
LLVMInitializeFunctionPassManager(functionPasses);
for (LLVMValueRef value = LLVMGetFirstFunction(Module);
value; value = LLVMGetNextFunction(value))
LLVMRunFunctionPassManager(functionPasses, value);
LLVMFinalizeFunctionPassManager(functionPasses);
LLVMRunPassManager(modulePasses, Module);
LLVMDisposePassManager(functionPasses);
LLVMDisposePassManager(modulePasses);
}
LLVMModuleRef Module; LLVMModuleRef Module;
LLVMValueRef Function; LLVMValueRef Function;
LLVMValueRef Function2; LLVMValueRef Function2;
@ -293,6 +360,29 @@ TEST_F(MCJITCAPITest, custom_memory_manager) {
EXPECT_TRUE(didCallAllocateCodeSection); EXPECT_TRUE(didCallAllocateCodeSection);
} }
TEST_F(MCJITCAPITest, stackmap_creates_compact_unwind_on_darwin) {
SKIP_UNSUPPORTED_PLATFORM;
buildFunctionThatUsesStackmap();
buildMCJITOptions();
useRoundTripSectionMemoryManager();
buildMCJITEngine();
buildAndRunOptPasses();
union {
void *raw;
int (*usable)();
} functionPointer;
functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
EXPECT_EQ(42, functionPointer.usable());
EXPECT_TRUE(didCallAllocateCodeSection);
EXPECT_TRUE(
Triple(HostTriple).getOS() != Triple::Darwin ||
didAllocateCompactUnwindSection);
}
TEST_F(MCJITCAPITest, reserve_allocation_space) { TEST_F(MCJITCAPITest, reserve_allocation_space) {
SKIP_UNSUPPORTED_PLATFORM; SKIP_UNSUPPORTED_PLATFORM;

View File

@ -9,7 +9,7 @@
LEVEL = ../../.. LEVEL = ../../..
TESTNAME = MCJIT TESTNAME = MCJIT
LINK_COMPONENTS := core jit mcjit native support LINK_COMPONENTS := core ipo jit mcjit native support
include $(LEVEL)/Makefile.config include $(LEVEL)/Makefile.config
include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest

View File

@ -666,6 +666,7 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
OS << " }\n"; OS << " }\n";
} else { } else {
OS << " return AttributeSet();\n"; OS << " return AttributeSet();\n";
OS << " }\n";
} }
} }