Stackmaps are used for OSR exits, which is a custom kind of unwinding. Hence, they
authorFilip Pizlo <fpizlo@apple.com>
Thu, 20 Feb 2014 23:57:31 +0000 (23:57 +0000)
committerFilip Pizlo <fpizlo@apple.com>
Thu, 20 Feb 2014 23:57:31 +0000 (23:57 +0000)
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

include/llvm/IR/Intrinsics.td
unittests/ExecutionEngine/MCJIT/CMakeLists.txt
unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp
unittests/ExecutionEngine/MCJIT/Makefile
utils/TableGen/IntrinsicEmitter.cpp

index ca05db4982ac771cc3f7c19087b2b334e0620af6..f8d8e79c9afdcceab0f6ae6b3c4026876c6355ff 100644 (file)
@@ -458,7 +458,8 @@ def int_invariant_end   : Intrinsic<[],
 //===------------------------ Stackmap Intrinsics -------------------------===//
 //
 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<[],
                                                  [llvm_i64_ty, llvm_i32_ty,
                                                   llvm_ptr_ty, llvm_i32_ty,
index a425b2478ac6b10a59bf39cdae9c1206f888ae3b..afa3f2a6f66b5ad3d4dfbe3f84efcff9cb0dcadd 100644 (file)
@@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS
   Analysis
   Core
   ExecutionEngine
+  IPO
   JIT
   MCJIT
   ScalarOpts
index a56d9c7b9c054bd0b843ca33ea3200c16fb17036..7a7d178623d87397a5bd3a97b933bad11c115d2c 100644 (file)
@@ -18,6 +18,7 @@
 #include "llvm-c/ExecutionEngine.h"
 #include "llvm-c/Target.h"
 #include "llvm-c/Transforms/Scalar.h"
+#include "llvm-c/Transforms/PassManagerBuilder.h"
 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
 #include "llvm/Support/Host.h"
 #include "gtest/gtest.h"
@@ -26,6 +27,7 @@
 using namespace llvm;
 
 static bool didCallAllocateCodeSection;
+static bool didAllocateCompactUnwindSection;
 
 static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size,
                                              unsigned alignment,
@@ -41,6 +43,8 @@ static uint8_t *roundTripAllocateDataSection(void *object, uintptr_t size,
                                              unsigned sectionID,
                                              const char *sectionName,
                                              LLVMBool isReadOnly) {
+  if (!strcmp(sectionName, "__compact_unwind"))
+    didAllocateCompactUnwindSection = true;
   return static_cast<SectionMemoryManager*>(object)->allocateDataSection(
     size, alignment, sectionID, sectionName, isReadOnly);
 }
@@ -135,6 +139,7 @@ protected:
   
   virtual void SetUp() {
     didCallAllocateCodeSection = false;
+    didAllocateCompactUnwindSection = false;
     Module = 0;
     Function = 0;
     Engine = 0;
@@ -168,6 +173,36 @@ protected:
     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() {
     Module = LLVMModuleCreateWithName("simple_module");
     
@@ -248,6 +283,38 @@ protected:
     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;
   LLVMValueRef Function;
   LLVMValueRef Function2;
@@ -293,6 +360,29 @@ TEST_F(MCJITCAPITest, custom_memory_manager) {
   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) {
   SKIP_UNSUPPORTED_PLATFORM;
   
index 454f83099d4b4e5338297c63aef3566482806884..c4dd740e05751a524a43aebb790281e049d90324 100644 (file)
@@ -9,7 +9,7 @@
 
 LEVEL = ../../..
 TESTNAME = MCJIT
-LINK_COMPONENTS := core jit mcjit native support
+LINK_COMPONENTS := core ipo jit mcjit native support
 
 include $(LEVEL)/Makefile.config
 include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest
index 173e50653274154483a2be8299d617ad89cbb11d..d366861992d587cc9e983a45991a17eeb10dc8e6 100644 (file)
@@ -666,6 +666,7 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
       OS << "      }\n";
     } else {
       OS << "      return AttributeSet();\n";
+      OS << "      }\n";
     }
   }