Title: [181990] trunk
Revision
181990
Author
[email protected]
Date
2015-03-25 18:26:56 -0700 (Wed, 25 Mar 2015)

Log Message

Use JITCompilationCanFail in more places, and make the fail path of JITCompilationMustSucceed a crash instead of attempting GC
https://bugs.webkit.org/show_bug.cgi?id=142993

Source/_javascript_Core:

Reviewed by Geoffrey Garen and Mark Lam.
        
This changes the most commonly invoked paths that relied on JITCompilationMustSucceed
into using JITCompilationCanFail and having a legit fallback path. This mostly involves
having the FTL JIT do the same trick as the DFG JIT in case of any memory allocation
failure, but also involves adding the same kind of thing to the stub generators in
Repatch.
        
Because of that change, there are relatively few uses of JITCompilationMustSucceed. Most
of those uses cannot handle a GC, and so cannot do releaseExecutableMemory(). Only a few,
like host call stub generation, could handle a GC, but those get invoked very rarely. So,
this patch changes the releaseExecutableMemory() call into a crash with some diagnostic
printout.
        
Also add a way of inducing executable allocation failure, so that we can test this.

* CMakeLists.txt:
* _javascript_Core.vcxproj/_javascript_Core.vcxproj:
* _javascript_Core.xcodeproj/project.pbxproj:
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::compile):
(JSC::DFG::JITCompiler::compileFunction):
(JSC::DFG::JITCompiler::link): Deleted.
(JSC::DFG::JITCompiler::linkFunction): Deleted.
* dfg/DFGJITCompiler.h:
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::compileInThreadImpl):
* ftl/FTLCompile.cpp:
(JSC::FTL::mmAllocateCodeSection):
(JSC::FTL::mmAllocateDataSection):
* ftl/FTLLink.cpp:
(JSC::FTL::link):
* ftl/FTLState.h:
* jit/ArityCheckFailReturnThunks.cpp:
(JSC::ArityCheckFailReturnThunks::returnPCsFor):
* jit/ExecutableAllocationFuzz.cpp: Added.
(JSC::numberOfExecutableAllocationFuzzChecks):
(JSC::doExecutableAllocationFuzzing):
* jit/ExecutableAllocationFuzz.h: Added.
(JSC::doExecutableAllocationFuzzingIfEnabled):
* jit/ExecutableAllocatorFixedVMPool.cpp:
(JSC::ExecutableAllocator::allocate):
* jit/JIT.cpp:
(JSC::JIT::privateCompile):
* jit/JITCompilationEffort.h:
* jit/Repatch.cpp:
(JSC::generateByIdStub):
(JSC::tryCacheGetByID):
(JSC::tryBuildGetByIDList):
(JSC::emitPutReplaceStub):
(JSC::emitPutTransitionStubAndGetOldStructure):
(JSC::tryCachePutByID):
(JSC::tryBuildPutByIdList):
(JSC::tryRepatchIn):
(JSC::linkPolymorphicCall):
* jsc.cpp:
(jscmain):
* runtime/Options.h:
* runtime/TestRunnerUtils.h:
* runtime/VM.cpp:
* tests/executableAllocationFuzz: Added.
* tests/executableAllocationFuzz.yaml: Added.
* tests/executableAllocationFuzz/v8-raytrace.js: Added.

Tools:

Reviewed by Mark Lam.
        
Bunch of support for testing executable allocation failure.

* Scripts/jsc-stress-test-helpers/js-executable-allocation-fuzz: Added.
(fail):
* Scripts/run-_javascript_core-tests:
(runJSCStressTests):
* Scripts/run-jsc-stress-tests:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/CMakeLists.txt (181989 => 181990)


--- trunk/Source/_javascript_Core/CMakeLists.txt	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/CMakeLists.txt	2015-03-26 01:26:56 UTC (rev 181990)
@@ -326,6 +326,7 @@
     jit/AssemblyHelpers.cpp
     jit/ArityCheckFailReturnThunks.cpp
     jit/BinarySwitch.cpp
+    jit/ExecutableAllocationFuzz.cpp
     jit/ExecutableAllocator.cpp
     jit/ExecutableAllocatorFixedVMPool.cpp
     jit/GCAwareJITStubRoutine.cpp

Modified: trunk/Source/_javascript_Core/ChangeLog (181989 => 181990)


--- trunk/Source/_javascript_Core/ChangeLog	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-03-26 01:26:56 UTC (rev 181990)
@@ -1,3 +1,72 @@
+2015-03-25  Filip Pizlo  <[email protected]>
+
+        Use JITCompilationCanFail in more places, and make the fail path of JITCompilationMustSucceed a crash instead of attempting GC
+        https://bugs.webkit.org/show_bug.cgi?id=142993
+
+        Reviewed by Geoffrey Garen and Mark Lam.
+        
+        This changes the most commonly invoked paths that relied on JITCompilationMustSucceed
+        into using JITCompilationCanFail and having a legit fallback path. This mostly involves
+        having the FTL JIT do the same trick as the DFG JIT in case of any memory allocation
+        failure, but also involves adding the same kind of thing to the stub generators in
+        Repatch.
+        
+        Because of that change, there are relatively few uses of JITCompilationMustSucceed. Most
+        of those uses cannot handle a GC, and so cannot do releaseExecutableMemory(). Only a few,
+        like host call stub generation, could handle a GC, but those get invoked very rarely. So,
+        this patch changes the releaseExecutableMemory() call into a crash with some diagnostic
+        printout.
+        
+        Also add a way of inducing executable allocation failure, so that we can test this.
+
+        * CMakeLists.txt:
+        * _javascript_Core.vcxproj/_javascript_Core.vcxproj:
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * dfg/DFGJITCompiler.cpp:
+        (JSC::DFG::JITCompiler::compile):
+        (JSC::DFG::JITCompiler::compileFunction):
+        (JSC::DFG::JITCompiler::link): Deleted.
+        (JSC::DFG::JITCompiler::linkFunction): Deleted.
+        * dfg/DFGJITCompiler.h:
+        * dfg/DFGPlan.cpp:
+        (JSC::DFG::Plan::compileInThreadImpl):
+        * ftl/FTLCompile.cpp:
+        (JSC::FTL::mmAllocateCodeSection):
+        (JSC::FTL::mmAllocateDataSection):
+        * ftl/FTLLink.cpp:
+        (JSC::FTL::link):
+        * ftl/FTLState.h:
+        * jit/ArityCheckFailReturnThunks.cpp:
+        (JSC::ArityCheckFailReturnThunks::returnPCsFor):
+        * jit/ExecutableAllocationFuzz.cpp: Added.
+        (JSC::numberOfExecutableAllocationFuzzChecks):
+        (JSC::doExecutableAllocationFuzzing):
+        * jit/ExecutableAllocationFuzz.h: Added.
+        (JSC::doExecutableAllocationFuzzingIfEnabled):
+        * jit/ExecutableAllocatorFixedVMPool.cpp:
+        (JSC::ExecutableAllocator::allocate):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompile):
+        * jit/JITCompilationEffort.h:
+        * jit/Repatch.cpp:
+        (JSC::generateByIdStub):
+        (JSC::tryCacheGetByID):
+        (JSC::tryBuildGetByIDList):
+        (JSC::emitPutReplaceStub):
+        (JSC::emitPutTransitionStubAndGetOldStructure):
+        (JSC::tryCachePutByID):
+        (JSC::tryBuildPutByIdList):
+        (JSC::tryRepatchIn):
+        (JSC::linkPolymorphicCall):
+        * jsc.cpp:
+        (jscmain):
+        * runtime/Options.h:
+        * runtime/TestRunnerUtils.h:
+        * runtime/VM.cpp:
+        * tests/executableAllocationFuzz: Added.
+        * tests/executableAllocationFuzz.yaml: Added.
+        * tests/executableAllocationFuzz/v8-raytrace.js: Added.
+
 2015-03-25  Mark Lam  <[email protected]>
 
         REGRESSION(169139): LLINT intermittently fails JSC testapi tests.

Modified: trunk/Source/_javascript_Core/_javascript_Core.vcxproj/_javascript_Core.vcxproj (181989 => 181990)


--- trunk/Source/_javascript_Core/_javascript_Core.vcxproj/_javascript_Core.vcxproj	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/_javascript_Core.vcxproj/_javascript_Core.vcxproj	2015-03-26 01:26:56 UTC (rev 181990)
@@ -598,6 +598,7 @@
     <ClCompile Include="..\jit\ArityCheckFailReturnThunks.cpp" />
     <ClCompile Include="..\jit\AssemblyHelpers.cpp" />
     <ClCompile Include="..\jit\BinarySwitch.cpp" />
+    <ClCompile Include="..\jit\ExecutableAllocationFuzz.cpp" />
     <ClCompile Include="..\jit\ExecutableAllocator.cpp" />
     <ClCompile Include="..\jit\ExecutableAllocatorFixedVMPool.cpp" />
     <ClCompile Include="..\jit\GCAwareJITStubRoutine.cpp" />
@@ -1340,6 +1341,7 @@
     <ClInclude Include="..\jit\BinarySwitch.h" />
     <ClInclude Include="..\jit\CCallHelpers.h" />
     <ClInclude Include="..\jit\CompactJITCodeMap.h" />
+    <ClInclude Include="..\jit\ExecutableAllocationFuzz.h" />
     <ClInclude Include="..\jit\ExecutableAllocator.h" />
     <ClInclude Include="..\jit\FPRInfo.h" />
     <ClInclude Include="..\jit\GCAwareJITStubRoutine.h" />

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (181989 => 181990)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2015-03-26 01:26:56 UTC (rev 181990)
@@ -646,6 +646,8 @@
 		0FEE98431A89227500754E93 /* SetupVarargsFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEE98421A89227500754E93 /* SetupVarargsFrame.cpp */; };
 		0FEFC9AA1681A3B300567F53 /* DFGOSRExitJumpPlaceholder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEFC9A71681A3B000567F53 /* DFGOSRExitJumpPlaceholder.cpp */; };
 		0FEFC9AB1681A3B600567F53 /* DFGOSRExitJumpPlaceholder.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEFC9A81681A3B000567F53 /* DFGOSRExitJumpPlaceholder.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		0FF054F91AC35B4400E5BE57 /* ExecutableAllocationFuzz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FF054F71AC35B4400E5BE57 /* ExecutableAllocationFuzz.cpp */; };
+		0FF054FA1AC35B4400E5BE57 /* ExecutableAllocationFuzz.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF054F81AC35B4400E5BE57 /* ExecutableAllocationFuzz.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0FF0F19916B729F6005DF95B /* DFGLongLivedState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB4B51C16B62772003F696B /* DFGLongLivedState.cpp */; };
 		0FF0F19B16B729FA005DF95B /* DFGLongLivedState.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB4B51D16B62772003F696B /* DFGLongLivedState.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0FF0F19C16B72A03005DF95B /* DFGNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB4B51E16B62772003F696B /* DFGNode.cpp */; };
@@ -2349,6 +2351,8 @@
 		0FEE98421A89227500754E93 /* SetupVarargsFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SetupVarargsFrame.cpp; sourceTree = "<group>"; };
 		0FEFC9A71681A3B000567F53 /* DFGOSRExitJumpPlaceholder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGOSRExitJumpPlaceholder.cpp; path = dfg/DFGOSRExitJumpPlaceholder.cpp; sourceTree = "<group>"; };
 		0FEFC9A81681A3B000567F53 /* DFGOSRExitJumpPlaceholder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGOSRExitJumpPlaceholder.h; path = dfg/DFGOSRExitJumpPlaceholder.h; sourceTree = "<group>"; };
+		0FF054F71AC35B4400E5BE57 /* ExecutableAllocationFuzz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExecutableAllocationFuzz.cpp; sourceTree = "<group>"; };
+		0FF054F81AC35B4400E5BE57 /* ExecutableAllocationFuzz.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExecutableAllocationFuzz.h; sourceTree = "<group>"; };
 		0FF4272F158EBD44004CB9FF /* Disassembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Disassembler.h; path = disassembler/Disassembler.h; sourceTree = "<group>"; };
 		0FF42730158EBD44004CB9FF /* UDis86Disassembler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UDis86Disassembler.cpp; path = disassembler/UDis86Disassembler.cpp; sourceTree = "<group>"; };
 		0FF42734158EBD94004CB9FF /* udis86_decode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = udis86_decode.c; path = disassembler/udis86/udis86_decode.c; sourceTree = "<group>"; };
@@ -3801,6 +3805,8 @@
 		1429D92C0ED22D7000B89619 /* jit */ = {
 			isa = PBXGroup;
 			children = (
+				0FF054F71AC35B4400E5BE57 /* ExecutableAllocationFuzz.cpp */,
+				0FF054F81AC35B4400E5BE57 /* ExecutableAllocationFuzz.h */,
 				0F7576D018E1FEE9002EF4CD /* AccessorCallJITStubRoutine.cpp */,
 				0F7576D118E1FEE9002EF4CD /* AccessorCallJITStubRoutine.h */,
 				0F6B1CC718641DF800845D97 /* ArityCheckFailReturnThunks.cpp */,
@@ -5619,6 +5625,7 @@
 				A704D90317A0BAA8006BA554 /* DFGAbstractInterpreter.h in Headers */,
 				A704D90417A0BAA8006BA554 /* DFGAbstractInterpreterInlines.h in Headers */,
 				0F620177143FCD3F0068B77C /* DFGAbstractValue.h in Headers */,
+				0FF054FA1AC35B4400E5BE57 /* ExecutableAllocationFuzz.h in Headers */,
 				0F66E16B14DF3F1600B7B2E4 /* DFGAdjacencyList.h in Headers */,
 				0FFB921816D02EB20055A5DB /* DFGAllocator.h in Headers */,
 				A737810C1799EA2E00817533 /* DFGAnalysis.h in Headers */,
@@ -7229,6 +7236,7 @@
 				0F2B66FA17B6B5AB00A7AE3F /* JSTypedArrayConstructors.cpp in Sources */,
 				0F2B66FC17B6B5AB00A7AE3F /* JSTypedArrayPrototypes.cpp in Sources */,
 				0F2B66FE17B6B5AB00A7AE3F /* JSTypedArrays.cpp in Sources */,
+				0FF054F91AC35B4400E5BE57 /* ExecutableAllocationFuzz.cpp in Sources */,
 				86E3C61A167BABEE006D760A /* JSValue.mm in Sources */,
 				14BD5A320A3E91F600BAF59C /* JSValueRef.cpp in Sources */,
 				147F39D7107EC37600427A48 /* JSEnvironmentRecord.cpp in Sources */,

Modified: trunk/Source/_javascript_Core/dfg/DFGJITCompiler.cpp (181989 => 181990)


--- trunk/Source/_javascript_Core/dfg/DFGJITCompiler.cpp	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/dfg/DFGJITCompiler.cpp	2015-03-26 01:26:56 UTC (rev 181990)
@@ -325,10 +325,7 @@
     // Create OSR entry trampolines if necessary.
     m_speculative->createOSREntries();
     setEndOfCode();
-}
 
-void JITCompiler::link()
-{
     auto linkBuffer = std::make_unique<LinkBuffer>(*m_vm, *this, m_codeBlock, JITCompilationCanFail);
     if (linkBuffer->didFailToAllocate()) {
         m_graph.m_plan.finalizer = std::make_unique<FailedFinalizer>(m_graph.m_plan);
@@ -412,7 +409,9 @@
 #else
     thunkReg = GPRInfo::regT5;
 #endif
-    move(TrustedImmPtr(m_vm->arityCheckFailReturnThunks->returnPCsFor(*m_vm, m_codeBlock->numParameters())), thunkReg);
+    CodeLocationLabel* arityThunkLabels =
+        m_vm->arityCheckFailReturnThunks->returnPCsFor(*m_vm, m_codeBlock->numParameters());
+    move(TrustedImmPtr(arityThunkLabels), thunkReg);
     loadPtr(BaseIndex(thunkReg, GPRInfo::regT0, timesPtr()), thunkReg);
     m_callArityFixup = call();
     jump(fromArityCheck);
@@ -426,10 +425,7 @@
     // Create OSR entry trampolines if necessary.
     m_speculative->createOSREntries();
     setEndOfCode();
-}
 
-void JITCompiler::linkFunction()
-{
     // === Link ===
     auto linkBuffer = std::make_unique<LinkBuffer>(*m_vm, *this, m_codeBlock, JITCompilationCanFail);
     if (linkBuffer->didFailToAllocate()) {

Modified: trunk/Source/_javascript_Core/dfg/DFGJITCompiler.h (181989 => 181990)


--- trunk/Source/_javascript_Core/dfg/DFGJITCompiler.h	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/dfg/DFGJITCompiler.h	2015-03-26 01:26:56 UTC (rev 181990)
@@ -111,9 +111,6 @@
     void compile();
     void compileFunction();
     
-    void link();
-    void linkFunction();
-
     // Accessors for properties.
     Graph& graph() { return m_graph; }
     

Modified: trunk/Source/_javascript_Core/dfg/DFGPlan.cpp (181989 => 181990)


--- trunk/Source/_javascript_Core/dfg/DFGPlan.cpp	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/dfg/DFGPlan.cpp	2015-03-26 01:26:56 UTC (rev 181990)
@@ -299,13 +299,10 @@
         dumpAndVerifyGraph(dfg, "Graph after optimization:");
         
         JITCompiler dataFlowJIT(dfg);
-        if (codeBlock->codeType() == FunctionCode) {
+        if (codeBlock->codeType() == FunctionCode)
             dataFlowJIT.compileFunction();
-            dataFlowJIT.linkFunction();
-        } else {
+        else
             dataFlowJIT.compile();
-            dataFlowJIT.link();
-        }
         
         return DFGPath;
     }
@@ -404,6 +401,11 @@
             FTL::fail(state);
             return FTLPath;
         }
+        
+        if (state.allocationFailed) {
+            FTL::fail(state);
+            return FTLPath;
+        }
 
         if (state.jitCode->stackmaps.stackSize() > Options::llvmMaxStackSize()) {
             FTL::fail(state);
@@ -411,6 +413,12 @@
         }
 
         FTL::link(state);
+        
+        if (state.allocationFailed) {
+            FTL::fail(state);
+            return FTLPath;
+        }
+        
         return FTLPath;
 #else
         RELEASE_ASSERT_NOT_REACHED();

Modified: trunk/Source/_javascript_Core/ftl/FTLCompile.cpp (181989 => 181990)


--- trunk/Source/_javascript_Core/ftl/FTLCompile.cpp	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/ftl/FTLCompile.cpp	2015-03-26 01:26:56 UTC (rev 181990)
@@ -59,8 +59,18 @@
     
     RefPtr<ExecutableMemoryHandle> result =
         state.graph.m_vm.executableAllocator.allocate(
-            state.graph.m_vm, size, state.graph.m_codeBlock, JITCompilationMustSucceed);
+            state.graph.m_vm, size, state.graph.m_codeBlock, JITCompilationCanFail);
     
+    if (!result) {
+        // Signal failure. This compilation will get tossed.
+        state.allocationFailed = true;
+        
+        // Fake an allocation, since LLVM cannot handle failures in the memory manager.
+        RefPtr<DataSection> fakeSection = adoptRef(new DataSection(size, jitAllocationGranule));
+        state.jitCode->addDataSection(fakeSection);
+        return bitwise_cast<uint8_t*>(fakeSection->base());
+    }
+    
     // LLVM used to put __compact_unwind in a code section. We keep this here defensively,
     // for clients that use older LLVMs.
     if (!strcmp(sectionName, SECTION_NAME("compact_unwind"))) {
@@ -344,7 +354,11 @@
         checkJIT.jumpToExceptionHandler();
 
         auto linkBuffer = std::make_unique<LinkBuffer>(
-            vm, checkJIT, codeBlock, JITCompilationMustSucceed);
+            vm, checkJIT, codeBlock, JITCompilationCanFail);
+        if (linkBuffer->didFailToAllocate()) {
+            state.allocationFailed = true;
+            return;
+        }
         linkBuffer->link(callLookupExceptionHandler, FunctionPtr(lookupExceptionHandler));
         linkBuffer->link(callLookupExceptionHandlerFromCallerFrame, FunctionPtr(lookupExceptionHandlerFromCallerFrame));
 
@@ -358,7 +372,11 @@
         RELEASE_ASSERT(didSeeUnwindInfo);
         
         auto linkBuffer = std::make_unique<LinkBuffer>(
-            vm, exitThunkGenerator, codeBlock, JITCompilationMustSucceed);
+            vm, exitThunkGenerator, codeBlock, JITCompilationCanFail);
+        if (linkBuffer->didFailToAllocate()) {
+            state.allocationFailed = true;
+            return;
+        }
         
         RELEASE_ASSERT(state.finalizer->osrExit.size() == state.jitCode->osrExit.size());
         
@@ -516,7 +534,11 @@
         exceptionTarget.link(&slowPathJIT);
         MacroAssembler::Jump exceptionJump = slowPathJIT.jump();
         
-        state.finalizer->sideCodeLinkBuffer = std::make_unique<LinkBuffer>(vm, slowPathJIT, codeBlock, JITCompilationMustSucceed);
+        state.finalizer->sideCodeLinkBuffer = std::make_unique<LinkBuffer>(vm, slowPathJIT, codeBlock, JITCompilationCanFail);
+        if (state.finalizer->sideCodeLinkBuffer->didFailToAllocate()) {
+            state.allocationFailed = true;
+            return;
+        }
         state.finalizer->sideCodeLinkBuffer->link(
             exceptionJump, state.finalizer->handleExceptionsLinkBuffer->entrypoint());
         
@@ -675,13 +697,17 @@
             dataLog("FATAL: Could not create LLVM execution engine: ", error, "\n");
             CRASH();
         }
+        
+        // At this point we no longer own the module.
+        LModule module = state.module;
+        state.module = nullptr;
 
         // The data layout also has to be set in the module. Get the data layout from the MCJIT and apply
         // it to the module.
         LLVMTargetMachineRef targetMachine = llvm->GetExecutionEngineTargetMachine(engine);
         LLVMTargetDataRef targetData = llvm->GetExecutionEngineTargetData(engine);
         char* stringRepOfTargetData = llvm->CopyStringRepOfTargetData(targetData);
-        llvm->SetDataLayout(state.module, stringRepOfTargetData);
+        llvm->SetDataLayout(module, stringRepOfTargetData);
         free(stringRepOfTargetData);
 
         LLVMPassManagerRef functionPasses = 0;
@@ -707,14 +733,14 @@
             llvm->AddCFGSimplificationPass(modulePasses);
             llvm->AddDeadStoreEliminationPass(modulePasses);
 
-            llvm->RunPassManager(modulePasses, state.module);
+            llvm->RunPassManager(modulePasses, module);
         } else {
             LLVMPassManagerBuilderRef passBuilder = llvm->PassManagerBuilderCreate();
             llvm->PassManagerBuilderSetOptLevel(passBuilder, Options::llvmOptimizationLevel());
             llvm->PassManagerBuilderUseInlinerWithThreshold(passBuilder, 275);
             llvm->PassManagerBuilderSetSizeLevel(passBuilder, Options::llvmSizeLevel());
         
-            functionPasses = llvm->CreateFunctionPassManagerForModule(state.module);
+            functionPasses = llvm->CreateFunctionPassManagerForModule(module);
             modulePasses = llvm->CreatePassManager();
         
             llvm->AddTargetData(llvm->GetExecutionEngineTargetData(engine), modulePasses);
@@ -725,11 +751,11 @@
             llvm->PassManagerBuilderDispose(passBuilder);
         
             llvm->InitializeFunctionPassManager(functionPasses);
-            for (LValue function = llvm->GetFirstFunction(state.module); function; function = llvm->GetNextFunction(function))
+            for (LValue function = llvm->GetFirstFunction(module); function; function = llvm->GetNextFunction(function))
                 llvm->RunFunctionPassManager(functionPasses, function);
             llvm->FinalizeFunctionPassManager(functionPasses);
         
-            llvm->RunPassManager(modulePasses, state.module);
+            llvm->RunPassManager(modulePasses, module);
         }
 
         if (shouldShowDisassembly() || verboseCompilationEnabled())
@@ -743,10 +769,14 @@
         llvm->DisposePassManager(modulePasses);
         llvm->DisposeExecutionEngine(engine);
     }
+
     if (safepointResult.didGetCancelled())
         return;
     RELEASE_ASSERT(!state.graph.m_vm.heap.isCollecting());
     
+    if (state.allocationFailed)
+        return;
+    
     if (shouldShowDisassembly()) {
         for (unsigned i = 0; i < state.jitCode->handles().size(); ++i) {
             ExecutableMemoryHandle* handle = state.jitCode->handles()[i].get();
@@ -802,6 +832,8 @@
         fixFunctionBasedOnStackMaps(
             state, state.graph.m_codeBlock, state.jitCode.get(), state.generatedFunction,
             recordMap, didSeeUnwindInfo);
+        if (state.allocationFailed)
+            return;
         
         if (shouldShowDisassembly() || Options::asyncDisassembly()) {
             for (unsigned i = 0; i < state.jitCode->handles().size(); ++i) {
@@ -830,8 +862,6 @@
             }
         }
     }
-    
-    state.module = 0; // We no longer own the module.
 }
 
 } } // namespace JSC::FTL

Modified: trunk/Source/_javascript_Core/ftl/FTLLink.cpp (181989 => 181990)


--- trunk/Source/_javascript_Core/ftl/FTLLink.cpp	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/ftl/FTLLink.cpp	2015-03-26 01:26:56 UTC (rev 181990)
@@ -171,13 +171,19 @@
         jit.emitFunctionEpilogue();
         mainPathJumps.append(jit.branchTest32(CCallHelpers::Zero, GPRInfo::regT0));
         jit.emitFunctionPrologue();
-        jit.move(CCallHelpers::TrustedImmPtr(vm.arityCheckFailReturnThunks->returnPCsFor(vm, codeBlock->numParameters())), GPRInfo::regT7);
+        CodeLocationLabel* arityThunkLabels =
+            vm.arityCheckFailReturnThunks->returnPCsFor(vm, codeBlock->numParameters());
+        jit.move(CCallHelpers::TrustedImmPtr(arityThunkLabels), GPRInfo::regT7);
         jit.loadPtr(CCallHelpers::BaseIndex(GPRInfo::regT7, GPRInfo::regT0, CCallHelpers::timesPtr()), GPRInfo::regT7);
         CCallHelpers::Call callArityFixup = jit.call();
         jit.emitFunctionEpilogue();
         mainPathJumps.append(jit.jump());
 
-        linkBuffer = std::make_unique<LinkBuffer>(vm, jit, codeBlock, JITCompilationMustSucceed);
+        linkBuffer = std::make_unique<LinkBuffer>(vm, jit, codeBlock, JITCompilationCanFail);
+        if (linkBuffer->didFailToAllocate()) {
+            state.allocationFailed = true;
+            return;
+        }
         linkBuffer->link(callArityCheck, codeBlock->m_isConstructor ? operationConstructArityCheck : operationCallArityCheck);
         linkBuffer->link(callArityFixup, FunctionPtr((vm.getCTIStub(arityFixupGenerator)).code().executableAddress()));
         linkBuffer->link(mainPathJumps, CodeLocationLabel(bitwise_cast<void*>(state.generatedFunction)));
@@ -195,7 +201,11 @@
         jit.emitFunctionEpilogue();
         CCallHelpers::Jump mainPathJump = jit.jump();
         
-        linkBuffer = std::make_unique<LinkBuffer>(vm, jit, codeBlock, JITCompilationMustSucceed);
+        linkBuffer = std::make_unique<LinkBuffer>(vm, jit, codeBlock, JITCompilationCanFail);
+        if (linkBuffer->didFailToAllocate()) {
+            state.allocationFailed = true;
+            return;
+        }
         linkBuffer->link(mainPathJump, CodeLocationLabel(bitwise_cast<void*>(state.generatedFunction)));
 
         state.jitCode->initializeAddressForCall(linkBuffer->locationOf(start));

Modified: trunk/Source/_javascript_Core/ftl/FTLState.h (181989 => 181990)


--- trunk/Source/_javascript_Core/ftl/FTLState.h	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/ftl/FTLState.h	2015-03-26 01:26:56 UTC (rev 181990)
@@ -66,6 +66,7 @@
     LContext context;
     LModule module;
     LValue function;
+    bool allocationFailed { false }; // Throw out the compilation once LLVM returns.
     RefPtr<JITCode> jitCode;
     GeneratedFunction generatedFunction;
     JITFinalizer* finalizer;

Modified: trunk/Source/_javascript_Core/jit/ArityCheckFailReturnThunks.cpp (181989 => 181990)


--- trunk/Source/_javascript_Core/jit/ArityCheckFailReturnThunks.cpp	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/jit/ArityCheckFailReturnThunks.cpp	2015-03-26 01:26:56 UTC (rev 181990)
@@ -97,7 +97,8 @@
         jit.jump(GPRInfo::regT2);
     }
     
-    LinkBuffer linkBuffer(vm, jit, GLOBAL_THUNK_ID);
+    // Sadly, we cannot fail here because the LLInt may need us.
+    LinkBuffer linkBuffer(vm, jit, GLOBAL_THUNK_ID, JITCompilationMustSucceed);
     
     unsigned returnPCsSize = numExpectedArgumentsIncludingThis / stackAlignmentRegisters() + 1;
     std::unique_ptr<CodeLocationLabel[]> returnPCs =

Added: trunk/Source/_javascript_Core/jit/ExecutableAllocationFuzz.cpp (0 => 181990)


--- trunk/Source/_javascript_Core/jit/ExecutableAllocationFuzz.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/jit/ExecutableAllocationFuzz.cpp	2015-03-26 01:26:56 UTC (rev 181990)
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "ExecutableAllocationFuzz.h"
+
+#include "TestRunnerUtils.h"
+#include <wtf/Atomics.h>
+#include <wtf/DataLog.h>
+
+namespace JSC {
+
+static Atomic<unsigned> s_numberOfExecutableAllocationFuzzChecks;
+unsigned numberOfExecutableAllocationFuzzChecks()
+{
+    return s_numberOfExecutableAllocationFuzzChecks.load();
+}
+
+ExecutableAllocationFuzzResult doExecutableAllocationFuzzing()
+{
+    ASSERT(Options::enableExecutableAllocationFuzz());
+    
+    unsigned oldValue;
+    unsigned newValue;
+    do {
+        oldValue = s_numberOfExecutableAllocationFuzzChecks.load();
+        newValue = oldValue + 1;
+    } while (!s_numberOfExecutableAllocationFuzzChecks.compareExchangeWeak(oldValue, newValue));
+    
+    if (newValue == Options::fireExecutableAllocationFuzzAt()) {
+        if (Options::verboseExecutableAllocationFuzz()) {
+            dataLog("Will pretend to fail executable allocation.\n");
+            WTFReportBacktrace();
+        }
+        return PretendToFailExecutableAllocation;
+    }
+    
+    if (Options::fireExecutableAllocationFuzzAtOrAfter()
+        && newValue >= Options::fireExecutableAllocationFuzzAtOrAfter()) {
+        if (Options::verboseExecutableAllocationFuzz()) {
+            dataLog("Will pretend to fail executable allocation.\n");
+            WTFReportBacktrace();
+        }
+        return PretendToFailExecutableAllocation;
+    }
+    
+    return AllowNormalExecutableAllocation;
+}
+
+} // namespace JSC
+

Added: trunk/Source/_javascript_Core/jit/ExecutableAllocationFuzz.h (0 => 181990)


--- trunk/Source/_javascript_Core/jit/ExecutableAllocationFuzz.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/jit/ExecutableAllocationFuzz.h	2015-03-26 01:26:56 UTC (rev 181990)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef ExecutableAllocationFuzz_h
+#define ExecutableAllocationFuzz_h
+
+#include "Options.h"
+
+namespace JSC {
+
+enum ExecutableAllocationFuzzResult {
+    AllowNormalExecutableAllocation,
+    PretendToFailExecutableAllocation
+};
+
+ExecutableAllocationFuzzResult doExecutableAllocationFuzzing();
+
+inline ExecutableAllocationFuzzResult doExecutableAllocationFuzzingIfEnabled()
+{
+    if (LIKELY(!Options::enableExecutableAllocationFuzz()))
+        return AllowNormalExecutableAllocation;
+    
+    return doExecutableAllocationFuzzing();
+}
+
+} // namespace JSC
+
+#endif // ExecutableAllocationFuzz_h
+

Modified: trunk/Source/_javascript_Core/jit/ExecutableAllocatorFixedVMPool.cpp (181989 => 181990)


--- trunk/Source/_javascript_Core/jit/ExecutableAllocatorFixedVMPool.cpp	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/jit/ExecutableAllocatorFixedVMPool.cpp	2015-03-26 01:26:56 UTC (rev 181990)
@@ -31,6 +31,7 @@
 #if ENABLE(EXECUTABLE_ALLOCATOR_FIXED)
 
 #include "CodeProfiling.h"
+#include "ExecutableAllocationFuzz.h"
 #include <errno.h>
 #if !PLATFORM(WIN)
 #include <unistd.h>
@@ -158,15 +159,24 @@
     return result;
 }
 
-PassRefPtr<ExecutableMemoryHandle> ExecutableAllocator::allocate(VM& vm, size_t sizeInBytes, void* ownerUID, JITCompilationEffort effort)
+PassRefPtr<ExecutableMemoryHandle> ExecutableAllocator::allocate(VM&, size_t sizeInBytes, void* ownerUID, JITCompilationEffort effort)
 {
+    if (effort != JITCompilationCanFail && Options::reportMustSucceedExecutableAllocations()) {
+        dataLog("Allocating ", sizeInBytes, " bytes of executable memory with JITCompilationMustSucceed.\n");
+        WTFReportBacktrace();
+    }
+    
+    if (effort == JITCompilationCanFail
+        && doExecutableAllocationFuzzingIfEnabled() == PretendToFailExecutableAllocation)
+        return nullptr;
+    
     RefPtr<ExecutableMemoryHandle> result = allocator->allocate(sizeInBytes, ownerUID);
     if (!result) {
-        if (effort == JITCompilationCanFail)
-            return result;
-        releaseExecutableMemory(vm);
-        result = allocator->allocate(sizeInBytes, ownerUID);
-        RELEASE_ASSERT(result);
+        if (effort != JITCompilationCanFail) {
+            dataLog("Ran out of executable memory while allocating ", sizeInBytes, " bytes.\n");
+            CRASH();
+        }
+        return nullptr;
     }
     return result.release();
 }

Modified: trunk/Source/_javascript_Core/jit/JIT.cpp (181989 => 181990)


--- trunk/Source/_javascript_Core/jit/JIT.cpp	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/jit/JIT.cpp	2015-03-26 01:26:56 UTC (rev 181990)
@@ -585,7 +585,9 @@
 #else
         thunkReg = GPRInfo::regT5;
 #endif
-        move(TrustedImmPtr(m_vm->arityCheckFailReturnThunks->returnPCsFor(*m_vm, m_codeBlock->numParameters())), thunkReg);
+        CodeLocationLabel* failThunkLabels =
+            m_vm->arityCheckFailReturnThunks->returnPCsFor(*m_vm, m_codeBlock->numParameters());
+        move(TrustedImmPtr(failThunkLabels), thunkReg);
         loadPtr(BaseIndex(thunkReg, regT0, timesPtr()), thunkReg);
         emitNakedCall(m_vm->getCTIStub(arityFixupGenerator).code());
 

Modified: trunk/Source/_javascript_Core/jit/JITCompilationEffort.h (181989 => 181990)


--- trunk/Source/_javascript_Core/jit/JITCompilationEffort.h	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/jit/JITCompilationEffort.h	2015-03-26 01:26:56 UTC (rev 181990)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions

Modified: trunk/Source/_javascript_Core/jit/Repatch.cpp (181989 => 181990)


--- trunk/Source/_javascript_Core/jit/Repatch.cpp	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/jit/Repatch.cpp	2015-03-26 01:26:56 UTC (rev 181990)
@@ -293,7 +293,7 @@
     return FunctionPtr(slot.customSetter());
 }
 
-static void generateByIdStub(
+static bool generateByIdStub(
     ExecState* exec, ByIdStubKind kind, const Identifier& propertyName,
     FunctionPtr custom, StructureStubInfo& stubInfo, StructureChain* chain, size_t count,
     PropertyOffset offset, Structure* structure, bool loadTargetFromProxy, WatchpointSet* watchpointSet,
@@ -574,7 +574,9 @@
     }
     emitRestoreScratch(stubJit, needToRestoreScratch, scratchGPR, success, fail, failureCases);
     
-    LinkBuffer patchBuffer(*vm, stubJit, exec->codeBlock());
+    LinkBuffer patchBuffer(*vm, stubJit, exec->codeBlock(), JITCompilationCanFail);
+    if (patchBuffer.didFailToAllocate())
+        return false;
     
     linkRestoreScratch(patchBuffer, needToRestoreScratch, success, fail, failureCases, successLabel, slowCaseLabel);
     if (kind == CallCustomGetter || kind == CallCustomSetter) {
@@ -601,6 +603,8 @@
         stubRoutine = adoptRef(new AccessorCallJITStubRoutine(code, *vm, WTF::move(callLinkInfo)));
     else
         stubRoutine = createJITStubRoutine(code, *vm, codeBlock->ownerExecutable(), true);
+    
+    return true;
 }
 
 enum InlineCacheAction {
@@ -687,7 +691,9 @@
 
             emitRestoreScratch(stubJit, needToRestoreScratch, scratchGPR, success, fail, failureCases);
             
-            LinkBuffer patchBuffer(*vm, stubJit, codeBlock);
+            LinkBuffer patchBuffer(*vm, stubJit, codeBlock, JITCompilationCanFail);
+            if (patchBuffer.didFailToAllocate())
+                return GiveUpOnCache;
 
             linkRestoreScratch(patchBuffer, needToRestoreScratch, stubInfo, success, fail, failureCases);
 
@@ -717,8 +723,10 @@
 
         MacroAssembler::Jump success = stubJit.jump();
 
-        LinkBuffer patchBuffer(*vm, stubJit, codeBlock);
-
+        LinkBuffer patchBuffer(*vm, stubJit, codeBlock, JITCompilationCanFail);
+        if (patchBuffer.didFailToAllocate())
+            return GiveUpOnCache;
+        
         patchBuffer.link(success, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone));
         patchBuffer.link(failure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToSlowCase));
 
@@ -844,11 +852,13 @@
     }
     
     RefPtr<JITStubRoutine> stubRoutine;
-    generateByIdStub(
+    bool result = generateByIdStub(
         exec, kindFor(slot), ident, customFor(slot), stubInfo, prototypeChain, count, offset, 
         structure, loadTargetFromProxy, slot.watchpointSet(), 
         stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone),
         CodeLocationLabel(list->currentSlowPathTarget(stubInfo)), stubRoutine);
+    if (!result)
+        return GiveUpOnCache;
     
     GetByIdAccess::AccessType accessType;
     if (slot.isCacheableValue())
@@ -901,7 +911,7 @@
     return operationPutByIdNonStrictBuildList;
 }
 
-static void emitPutReplaceStub(
+static bool emitPutReplaceStub(
     ExecState* exec,
     const Identifier&,
     const PutPropertySlot& slot,
@@ -968,7 +978,10 @@
         failure = badStructure;
     }
     
-    LinkBuffer patchBuffer(*vm, stubJit, exec->codeBlock());
+    LinkBuffer patchBuffer(*vm, stubJit, exec->codeBlock(), JITCompilationCanFail);
+    if (patchBuffer.didFailToAllocate())
+        return false;
+    
     patchBuffer.link(success, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone));
     patchBuffer.link(failure, failureLabel);
             
@@ -977,6 +990,8 @@
         ("PutById replace stub for %s, return point %p",
             toCString(*exec->codeBlock()).data(), stubInfo.callReturnLocation.labelAtOffset(
                 stubInfo.patch.deltaCallToDone).executableAddress()));
+    
+    return true;
 }
 
 static Structure* emitPutTransitionStubAndGetOldStructure(ExecState* exec, VM* vm, Structure*& structure, const Identifier& ident, 
@@ -1213,7 +1228,10 @@
         successInSlowPath = stubJit.jump();
     }
     
-    LinkBuffer patchBuffer(*vm, stubJit, exec->codeBlock());
+    LinkBuffer patchBuffer(*vm, stubJit, exec->codeBlock(), JITCompilationCanFail);
+    if (patchBuffer.didFailToAllocate())
+        return nullptr;
+    
     patchBuffer.link(success, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone));
     if (allocator.didReuseRegisters())
         patchBuffer.link(failure, failureLabel);
@@ -1308,13 +1326,15 @@
         PolymorphicPutByIdList* list;
         list = PolymorphicPutByIdList::from(putKind, stubInfo);
 
-        generateByIdStub(
+        bool result = generateByIdStub(
             exec, kindFor(slot), ident, customFor(slot), stubInfo, prototypeChain, count,
             offset, structure, false, nullptr,
             stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone),
             stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToSlowCase),
             stubRoutine);
-
+        if (!result)
+            return GiveUpOnCache;
+        
         list->addAccess(PutByIdAccess::setter(
             *vm, codeBlock->ownerExecutable(),
             slot.isCacheableSetter() ? PutByIdAccess::Setter : PutByIdAccess::CustomSetter,
@@ -1383,10 +1403,12 @@
             structure->didCachePropertyReplacement(*vm, slot.cachedOffset());
             
             // We're now committed to creating the stub. Mogrify the meta-data accordingly.
-            emitPutReplaceStub(
+            bool result = emitPutReplaceStub(
                 exec, propertyName, slot, stubInfo, 
                 structure, CodeLocationLabel(list->currentSlowPathTarget()), stubRoutine);
-
+            if (!result)
+                return GiveUpOnCache;
+            
             list->addAccess(
                 PutByIdAccess::replace(
                     *vm, codeBlock->ownerExecutable(),
@@ -1416,13 +1438,15 @@
         PolymorphicPutByIdList* list;
         list = PolymorphicPutByIdList::from(putKind, stubInfo);
 
-        generateByIdStub(
+        bool result = generateByIdStub(
             exec, kindFor(slot), propertyName, customFor(slot), stubInfo, prototypeChain, count,
             offset, structure, false, nullptr,
             stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone),
             CodeLocationLabel(list->currentSlowPathTarget()),
             stubRoutine);
-
+        if (!result)
+            return GiveUpOnCache;
+        
         list->addAccess(PutByIdAccess::setter(
             *vm, codeBlock->ownerExecutable(),
             slot.isCacheableSetter() ? PutByIdAccess::Setter : PutByIdAccess::CustomSetter,
@@ -1548,8 +1572,10 @@
         
         emitRestoreScratch(stubJit, needToRestoreScratch, scratchGPR, success, fail, failureCases);
         
-        LinkBuffer patchBuffer(*vm, stubJit, exec->codeBlock());
-
+        LinkBuffer patchBuffer(*vm, stubJit, exec->codeBlock(), JITCompilationCanFail);
+        if (patchBuffer.didFailToAllocate())
+            return GiveUpOnCache;
+        
         linkRestoreScratch(patchBuffer, needToRestoreScratch, success, fail, failureCases, successLabel, slowCaseLabel);
         
         stubRoutine = FINALIZE_CODE_FOR_STUB(
@@ -1851,7 +1877,11 @@
     stubJit.restoreReturnAddressBeforeReturn(GPRInfo::regT4);
     AssemblyHelpers::Jump slow = stubJit.jump();
         
-    LinkBuffer patchBuffer(*vm, stubJit, callerCodeBlock);
+    LinkBuffer patchBuffer(*vm, stubJit, callerCodeBlock, JITCompilationCanFail);
+    if (patchBuffer.didFailToAllocate()) {
+        linkVirtualFor(exec, callLinkInfo, CodeForCall, registers);
+        return;
+    }
     
     RELEASE_ASSERT(callCases.size() == calls.size());
     for (CallToCodePtr callToCodePtr : calls) {

Modified: trunk/Source/_javascript_Core/jsc.cpp (181989 => 181990)


--- trunk/Source/_javascript_Core/jsc.cpp	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/jsc.cpp	2015-03-26 01:26:56 UTC (rev 181990)
@@ -1498,6 +1498,10 @@
 #if ENABLE(JIT)
         if (Options::enableExceptionFuzz())
             printf("JSC EXCEPTION FUZZ: encountered %u checks.\n", numberOfExceptionFuzzChecks());
+        bool fireAtEnabled =
+            Options::fireExecutableAllocationFuzzAt() || Options::fireExecutableAllocationFuzzAtOrAfter();
+        if (Options::enableExecutableAllocationFuzz() && (!fireAtEnabled || Options::verboseExecutableAllocationFuzz()))
+            printf("JSC EXECUTABLE ALLOCATION FUZZ: encountered %u checks.\n", numberOfExecutableAllocationFuzzChecks());
 #endif
     }
     

Modified: trunk/Source/_javascript_Core/runtime/Options.h (181989 => 181990)


--- trunk/Source/_javascript_Core/runtime/Options.h	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/runtime/Options.h	2015-03-26 01:26:56 UTC (rev 181990)
@@ -97,6 +97,8 @@
     v(bool, useDFGJIT, true) \
     v(bool, useRegExpJIT, true) \
     \
+    v(bool, reportMustSucceedExecutableAllocations, false) \
+    \
     v(unsigned, maxPerThreadStackUsage, 4 * MB) \
     v(unsigned, reservedZoneSize, 128 * KB) \
     v(unsigned, errorModeReservedZoneSize, 64 * KB) \
@@ -291,7 +293,12 @@
     v(unsigned, numberOfGCCyclesToRecordForVerification, 3) \
     \
     v(bool, enableExceptionFuzz, false) \
-    v(unsigned, fireExceptionFuzzAt, 0)
+    v(unsigned, fireExceptionFuzzAt, 0) \
+    \
+    v(bool, enableExecutableAllocationFuzz, false) \
+    v(unsigned, fireExecutableAllocationFuzzAt, 0) \
+    v(unsigned, fireExecutableAllocationFuzzAtOrAfter, 0) \
+    v(bool, verboseExecutableAllocationFuzz, false)
 
 class Options {
 public:

Modified: trunk/Source/_javascript_Core/runtime/TestRunnerUtils.h (181989 => 181990)


--- trunk/Source/_javascript_Core/runtime/TestRunnerUtils.h	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/runtime/TestRunnerUtils.h	2015-03-26 01:26:56 UTC (rev 181990)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -45,6 +45,7 @@
 JS_EXPORT_PRIVATE JSValue optimizeNextInvocation(ExecState*);
 
 JS_EXPORT_PRIVATE unsigned numberOfExceptionFuzzChecks();
+JS_EXPORT_PRIVATE unsigned numberOfExecutableAllocationFuzzChecks();
 
 } // namespace JSC
 

Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (181989 => 181990)


--- trunk/Source/_javascript_Core/runtime/VM.cpp	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp	2015-03-26 01:26:56 UTC (rev 181990)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2011, 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2011, 2013-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions

Added: trunk/Source/_javascript_Core/tests/executableAllocationFuzz/v8-raytrace.js (0 => 181990)


--- trunk/Source/_javascript_Core/tests/executableAllocationFuzz/v8-raytrace.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/executableAllocationFuzz/v8-raytrace.js	2015-03-26 01:26:56 UTC (rev 181990)
@@ -0,0 +1,902 @@
+// The ray tracer code in this file is written by Adam Burmister. It
+// is available in its original form from:
+//
+//   http://labs.flog.nz.co/raytracer/
+//
+// It has been modified slightly by Google to work as a standalone
+// benchmark, but the all the computational code remains
+// untouched. This file also contains a copy of parts of the Prototype
+// _javascript_ framework which is used by the ray tracer.
+
+// Variable used to hold a number that can be used to verify that
+// the scene was ray traced correctly.
+var checkNumber;
+
+
+// ------------------------------------------------------------------------
+// ------------------------------------------------------------------------
+
+// The following is a copy of parts of the Prototype _javascript_ library:
+
+// Prototype _javascript_ framework, version 1.5.0
+// (c) 2005-2007 Sam Stephenson
+//
+// Prototype is freely distributable under the terms of an MIT-style license.
+// For details, see the Prototype web site: http://prototype.conio.net/
+
+
+var Class = {
+  create: function() {
+    return function() {
+      this.initialize.apply(this, arguments);
+    }
+  }
+};
+
+
+Object.extend = function(destination, source) {
+  for (var property in source) {
+    destination[property] = source[property];
+  }
+  return destination;
+};
+
+
+// ------------------------------------------------------------------------
+// ------------------------------------------------------------------------
+
+// The rest of this file is the actual ray tracer written by Adam
+// Burmister. It's a concatenation of the following files:
+//
+//   flog/color.js
+//   flog/light.js
+//   flog/vector.js
+//   flog/ray.js
+//   flog/scene.js
+//   flog/material/basematerial.js
+//   flog/material/solid.js
+//   flog/material/chessboard.js
+//   flog/shape/baseshape.js
+//   flog/shape/sphere.js
+//   flog/shape/plane.js
+//   flog/intersectioninfo.js
+//   flog/camera.js
+//   flog/background.js
+//   flog/engine.js
+
+
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Color = Class.create();
+
+Flog.RayTracer.Color.prototype = {
+    red : 0.0,
+    green : 0.0,
+    blue : 0.0,
+
+    initialize : function(r, g, b) {
+        if(!r) r = 0.0;
+        if(!g) g = 0.0;
+        if(!b) b = 0.0;
+
+        this.red = r;
+        this.green = g;
+        this.blue = b;
+    },
+
+    add : function(c1, c2){
+        var result = new Flog.RayTracer.Color(0,0,0);
+
+        result.red = c1.red + c2.red;
+        result.green = c1.green + c2.green;
+        result.blue = c1.blue + c2.blue;
+
+        return result;
+    },
+
+    addScalar: function(c1, s){
+        var result = new Flog.RayTracer.Color(0,0,0);
+
+        result.red = c1.red + s;
+        result.green = c1.green + s;
+        result.blue = c1.blue + s;
+
+        result.limit();
+
+        return result;
+    },
+
+    subtract: function(c1, c2){
+        var result = new Flog.RayTracer.Color(0,0,0);
+
+        result.red = c1.red - c2.red;
+        result.green = c1.green - c2.green;
+        result.blue = c1.blue - c2.blue;
+
+        return result;
+    },
+
+    multiply : function(c1, c2) {
+        var result = new Flog.RayTracer.Color(0,0,0);
+
+        result.red = c1.red * c2.red;
+        result.green = c1.green * c2.green;
+        result.blue = c1.blue * c2.blue;
+
+        return result;
+    },
+
+    multiplyScalar : function(c1, f) {
+        var result = new Flog.RayTracer.Color(0,0,0);
+
+        result.red = c1.red * f;
+        result.green = c1.green * f;
+        result.blue = c1.blue * f;
+
+        return result;
+    },
+
+    divideFactor : function(c1, f) {
+        var result = new Flog.RayTracer.Color(0,0,0);
+
+        result.red = c1.red / f;
+        result.green = c1.green / f;
+        result.blue = c1.blue / f;
+
+        return result;
+    },
+
+    limit: function(){
+        this.red = (this.red > 0.0) ? ( (this.red > 1.0) ? 1.0 : this.red ) : 0.0;
+        this.green = (this.green > 0.0) ? ( (this.green > 1.0) ? 1.0 : this.green ) : 0.0;
+        this.blue = (this.blue > 0.0) ? ( (this.blue > 1.0) ? 1.0 : this.blue ) : 0.0;
+    },
+
+    distance : function(color) {
+        var d = Math.abs(this.red - color.red) + Math.abs(this.green - color.green) + Math.abs(this.blue - color.blue);
+        return d;
+    },
+
+    blend: function(c1, c2, w){
+        var result = new Flog.RayTracer.Color(0,0,0);
+        result = Flog.RayTracer.Color.prototype.add(
+                    Flog.RayTracer.Color.prototype.multiplyScalar(c1, 1 - w),
+                    Flog.RayTracer.Color.prototype.multiplyScalar(c2, w)
+                  );
+        return result;
+    },
+
+    brightness : function() {
+        var r = Math.floor(this.red*255);
+        var g = Math.floor(this.green*255);
+        var b = Math.floor(this.blue*255);
+        return (r * 77 + g * 150 + b * 29) >> 8;
+    },
+
+    toString : function () {
+        var r = Math.floor(this.red*255);
+        var g = Math.floor(this.green*255);
+        var b = Math.floor(this.blue*255);
+
+        return "rgb("+ r +","+ g +","+ b +")";
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Light = Class.create();
+
+Flog.RayTracer.Light.prototype = {
+    position: null,
+    color: null,
+    intensity: 10.0,
+
+    initialize : function(pos, color, intensity) {
+        this.position = pos;
+        this.color = color;
+        this.intensity = (intensity ? intensity : 10.0);
+    },
+
+    toString : function () {
+        return 'Light [' + this.position.x + ',' + this.position.y + ',' + this.position.z + ']';
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Vector = Class.create();
+
+Flog.RayTracer.Vector.prototype = {
+    x : 0.0,
+    y : 0.0,
+    z : 0.0,
+
+    initialize : function(x, y, z) {
+        this.x = (x ? x : 0);
+        this.y = (y ? y : 0);
+        this.z = (z ? z : 0);
+    },
+
+    copy: function(vector){
+        this.x = vector.x;
+        this.y = vector.y;
+        this.z = vector.z;
+    },
+
+    normalize : function() {
+        var m = this.magnitude();
+        return new Flog.RayTracer.Vector(this.x / m, this.y / m, this.z / m);
+    },
+
+    magnitude : function() {
+        return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z));
+    },
+
+    cross : function(w) {
+        return new Flog.RayTracer.Vector(
+                                            -this.z * w.y + this.y * w.z,
+                                           this.z * w.x - this.x * w.z,
+                                          -this.y * w.x + this.x * w.y);
+    },
+
+    dot : function(w) {
+        return this.x * w.x + this.y * w.y + this.z * w.z;
+    },
+
+    add : function(v, w) {
+        return new Flog.RayTracer.Vector(w.x + v.x, w.y + v.y, w.z + v.z);
+    },
+
+    subtract : function(v, w) {
+        if(!w || !v) throw 'Vectors must be defined [' + v + ',' + w + ']';
+        return new Flog.RayTracer.Vector(v.x - w.x, v.y - w.y, v.z - w.z);
+    },
+
+    multiplyVector : function(v, w) {
+        return new Flog.RayTracer.Vector(v.x * w.x, v.y * w.y, v.z * w.z);
+    },
+
+    multiplyScalar : function(v, w) {
+        return new Flog.RayTracer.Vector(v.x * w, v.y * w, v.z * w);
+    },
+
+    toString : function () {
+        return 'Vector [' + this.x + ',' + this.y + ',' + this.z + ']';
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Ray = Class.create();
+
+Flog.RayTracer.Ray.prototype = {
+    position : null,
+    direction : null,
+    initialize : function(pos, dir) {
+        this.position = pos;
+        this.direction = dir;
+    },
+
+    toString : function () {
+        return 'Ray [' + this.position + ',' + this.direction + ']';
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Scene = Class.create();
+
+Flog.RayTracer.Scene.prototype = {
+    camera : null,
+    shapes : [],
+    lights : [],
+    background : null,
+
+    initialize : function() {
+        this.camera = new Flog.RayTracer.Camera(
+            new Flog.RayTracer.Vector(0,0,-5),
+            new Flog.RayTracer.Vector(0,0,1),
+            new Flog.RayTracer.Vector(0,1,0)
+        );
+        this.shapes = new Array();
+        this.lights = new Array();
+        this.background = "" Flog.RayTracer.Background(new Flog.RayTracer.Color(0,0,0.5), 0.2);
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+if(typeof(Flog.RayTracer.Material) == 'undefined') Flog.RayTracer.Material = {};
+
+Flog.RayTracer.Material.BaseMaterial = Class.create();
+
+Flog.RayTracer.Material.BaseMaterial.prototype = {
+
+    gloss: 2.0,             // [0...infinity] 0 = matt
+    transparency: 0.0,      // 0=opaque
+    reflection: 0.0,        // [0...infinity] 0 = no reflection
+    refraction: 0.50,
+    hasTexture: false,
+
+    initialize : function() {
+
+    },
+
+    getColor: function(u, v){
+
+    },
+
+    wrapUp: function(t){
+        t = t % 2.0;
+        if(t < -1) t += 2.0;
+        if(t >= 1) t -= 2.0;
+        return t;
+    },
+
+    toString : function () {
+        return 'Material [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Material.Solid = Class.create();
+
+Flog.RayTracer.Material.Solid.prototype = Object.extend(
+    new Flog.RayTracer.Material.BaseMaterial(), {
+        initialize : function(color, reflection, refraction, transparency, gloss) {
+            this.color = color;
+            this.reflection = reflection;
+            this.transparency = transparency;
+            this.gloss = gloss;
+            this.hasTexture = false;
+        },
+
+        getColor: function(u, v){
+            return this.color;
+        },
+
+        toString : function () {
+            return 'SolidMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
+        }
+    }
+);
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Material.Chessboard = Class.create();
+
+Flog.RayTracer.Material.Chessboard.prototype = Object.extend(
+    new Flog.RayTracer.Material.BaseMaterial(), {
+        colorEven: null,
+        colorOdd: null,
+        density: 0.5,
+
+        initialize : function(colorEven, colorOdd, reflection, transparency, gloss, density) {
+            this.colorEven = colorEven;
+            this.colorOdd = colorOdd;
+            this.reflection = reflection;
+            this.transparency = transparency;
+            this.gloss = gloss;
+            this.density = density;
+            this.hasTexture = true;
+        },
+
+        getColor: function(u, v){
+            var t = this.wrapUp(u * this.density) * this.wrapUp(v * this.density);
+
+            if(t < 0.0)
+                return this.colorEven;
+            else
+                return this.colorOdd;
+        },
+
+        toString : function () {
+            return 'ChessMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
+        }
+    }
+);
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {};
+
+Flog.RayTracer.Shape.Sphere = Class.create();
+
+Flog.RayTracer.Shape.Sphere.prototype = {
+    initialize : function(pos, radius, material) {
+        this.radius = radius;
+        this.position = pos;
+        this.material = material;
+    },
+
+    intersect: function(ray){
+        var info = new Flog.RayTracer.IntersectionInfo();
+        info.shape = this;
+
+        var dst = Flog.RayTracer.Vector.prototype.subtract(ray.position, this.position);
+
+        var B = dst.dot(ray.direction);
+        var C = dst.dot(dst) - (this.radius * this.radius);
+        var D = (B * B) - C;
+
+        if(D > 0){ // intersection!
+            info.isHit = true;
+            info.distance = (-B) - Math.sqrt(D);
+            info.position = Flog.RayTracer.Vector.prototype.add(
+                                                ray.position,
+                                                Flog.RayTracer.Vector.prototype.multiplyScalar(
+                                                    ray.direction,
+                                                    info.distance
+                                                )
+                                            );
+            info.normal = Flog.RayTracer.Vector.prototype.subtract(
+                                            info.position,
+                                            this.position
+                                        ).normalize();
+
+            info.color = this.material.getColor(0,0);
+        } else {
+            info.isHit = false;
+        }
+        return info;
+    },
+
+    toString : function () {
+        return 'Sphere [position=' + this.position + ', radius=' + this.radius + ']';
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {};
+
+Flog.RayTracer.Shape.Plane = Class.create();
+
+Flog.RayTracer.Shape.Plane.prototype = {
+    d: 0.0,
+
+    initialize : function(pos, d, material) {
+        this.position = pos;
+        this.d = d;
+        this.material = material;
+    },
+
+    intersect: function(ray){
+        var info = new Flog.RayTracer.IntersectionInfo();
+
+        var Vd = this.position.dot(ray.direction);
+        if(Vd == 0) return info; // no intersection
+
+        var t = -(this.position.dot(ray.position) + this.d) / Vd;
+        if(t <= 0) return info;
+
+        info.shape = this;
+        info.isHit = true;
+        info.position = Flog.RayTracer.Vector.prototype.add(
+                                            ray.position,
+                                            Flog.RayTracer.Vector.prototype.multiplyScalar(
+                                                ray.direction,
+                                                t
+                                            )
+                                        );
+        info.normal = this.position;
+        info.distance = t;
+
+        if(this.material.hasTexture){
+            var vU = new Flog.RayTracer.Vector(this.position.y, this.position.z, -this.position.x);
+            var vV = vU.cross(this.position);
+            var u = info.position.dot(vU);
+            var v = info.position.dot(vV);
+            info.color = this.material.getColor(u,v);
+        } else {
+            info.color = this.material.getColor(0,0);
+        }
+
+        return info;
+    },
+
+    toString : function () {
+        return 'Plane [' + this.position + ', d=' + this.d + ']';
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.IntersectionInfo = Class.create();
+
+Flog.RayTracer.IntersectionInfo.prototype = {
+    isHit: false,
+    hitCount: 0,
+    shape: null,
+    position: null,
+    normal: null,
+    color: null,
+    distance: null,
+
+    initialize : function() {
+        this.color = new Flog.RayTracer.Color(0,0,0);
+    },
+
+    toString : function () {
+        return 'Intersection [' + this.position + ']';
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Camera = Class.create();
+
+Flog.RayTracer.Camera.prototype = {
+    position: null,
+    lookAt: null,
+    equator: null,
+    up: null,
+    screen: null,
+
+    initialize : function(pos, lookAt, up) {
+        this.position = pos;
+        this.lookAt = lookAt;
+        this.up = up;
+        this.equator = lookAt.normalize().cross(this.up);
+        this.screen = Flog.RayTracer.Vector.prototype.add(this.position, this.lookAt);
+    },
+
+    getRay: function(vx, vy){
+        var pos = Flog.RayTracer.Vector.prototype.subtract(
+            this.screen,
+            Flog.RayTracer.Vector.prototype.subtract(
+                Flog.RayTracer.Vector.prototype.multiplyScalar(this.equator, vx),
+                Flog.RayTracer.Vector.prototype.multiplyScalar(this.up, vy)
+            )
+        );
+        pos.y = pos.y * -1;
+        var dir = Flog.RayTracer.Vector.prototype.subtract(
+            pos,
+            this.position
+        );
+
+        var ray = new Flog.RayTracer.Ray(pos, dir.normalize());
+
+        return ray;
+    },
+
+    toString : function () {
+        return 'Ray []';
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Background = ""
+
+Flog.RayTracer.Background.prototype = {
+    color : null,
+    ambience : 0.0,
+
+    initialize : function(color, ambience) {
+        this.color = color;
+        this.ambience = ambience;
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Engine = Class.create();
+
+Flog.RayTracer.Engine.prototype = {
+    canvas: null, /* 2d context we can render to */
+
+    initialize: function(options){
+        this.options = Object.extend({
+                canvasHeight: 100,
+                canvasWidth: 100,
+                pixelWidth: 2,
+                pixelHeight: 2,
+                renderDiffuse: false,
+                renderShadows: false,
+                renderHighlights: false,
+                renderReflections: false,
+                rayDepth: 2
+            }, options || {});
+
+        this.options.canvasHeight /= this.options.pixelHeight;
+        this.options.canvasWidth /= this.options.pixelWidth;
+
+        /* TODO: dynamically include other scripts */
+    },
+
+    setPixel: function(x, y, color){
+        var pxW, pxH;
+        pxW = this.options.pixelWidth;
+        pxH = this.options.pixelHeight;
+
+        if (this.canvas) {
+          this.canvas.fillStyle = color.toString();
+          this.canvas.fillRect (x * pxW, y * pxH, pxW, pxH);
+        } else {
+          if (x ===  y) {
+            checkNumber += color.brightness();
+          }
+          // print(x * pxW, y * pxH, pxW, pxH);
+        }
+    },
+
+    renderScene: function(scene, canvas){
+        checkNumber = 0;
+        /* Get canvas */
+        if (canvas) {
+          this.canvas = canvas.getContext("2d");
+        } else {
+          this.canvas = null;
+        }
+
+        var canvasHeight = this.options.canvasHeight;
+        var canvasWidth = this.options.canvasWidth;
+
+        for(var y=0; y < canvasHeight; y++){
+            for(var x=0; x < canvasWidth; x++){
+                var yp = y * 1.0 / canvasHeight * 2 - 1;
+          		var xp = x * 1.0 / canvasWidth * 2 - 1;
+
+          		var ray = scene.camera.getRay(xp, yp);
+
+          		var color = this.getPixelColor(ray, scene);
+
+            	this.setPixel(x, y, color);
+            }
+        }
+        if (checkNumber !== 2321) {
+          throw new Error("Scene rendered incorrectly");
+        }
+    },
+
+    getPixelColor: function(ray, scene){
+        var info = this.testIntersection(ray, scene, null);
+        if(info.isHit){
+            var color = this.rayTrace(info, ray, scene, 0);
+            return color;
+        }
+        return scene.background.color;
+    },
+
+    testIntersection: function(ray, scene, exclude){
+        var hits = 0;
+        var best = new Flog.RayTracer.IntersectionInfo();
+        best.distance = 2000;
+
+        for(var i=0; i<scene.shapes.length; i++){
+            var shape = scene.shapes[i];
+
+            if(shape != exclude){
+                var info = shape.intersect(ray);
+                if(info.isHit && info.distance >= 0 && info.distance < best.distance){
+                    best = info;
+                    hits++;
+                }
+            }
+        }
+        best.hitCount = hits;
+        return best;
+    },
+
+    getReflectionRay: function(P,N,V){
+        var c1 = -N.dot(V);
+        var R1 = Flog.RayTracer.Vector.prototype.add(
+            Flog.RayTracer.Vector.prototype.multiplyScalar(N, 2*c1),
+            V
+        );
+        return new Flog.RayTracer.Ray(P, R1);
+    },
+
+    rayTrace: function(info, ray, scene, depth){
+        // Calc ambient
+        var color = Flog.RayTracer.Color.prototype.multiplyScalar(info.color, scene.background.ambience);
+        var oldColor = color;
+        var shininess = Math.pow(10, info.shape.material.gloss + 1);
+
+        for(var i=0; i<scene.lights.length; i++){
+            var light = scene.lights[i];
+
+            // Calc diffuse lighting
+            var v = Flog.RayTracer.Vector.prototype.subtract(
+                                light.position,
+                                info.position
+                            ).normalize();
+
+            if(this.options.renderDiffuse){
+                var L = v.dot(info.normal);
+                if(L > 0.0){
+                    color = Flog.RayTracer.Color.prototype.add(
+                                        color,
+                                        Flog.RayTracer.Color.prototype.multiply(
+                                            info.color,
+                                            Flog.RayTracer.Color.prototype.multiplyScalar(
+                                                light.color,
+                                                L
+                                            )
+                                        )
+                                    );
+                }
+            }
+
+            // The greater the depth the more accurate the colours, but
+            // this is exponentially (!) expensive
+            if(depth <= this.options.rayDepth){
+          // calculate reflection ray
+          if(this.options.renderReflections && info.shape.material.reflection > 0)
+          {
+              var reflectionRay = this.getReflectionRay(info.position, info.normal, ray.direction);
+              var refl = this.testIntersection(reflectionRay, scene, info.shape);
+
+              if (refl.isHit && refl.distance > 0){
+                  refl.color = this.rayTrace(refl, reflectionRay, scene, depth + 1);
+              } else {
+                  refl.color = scene.background.color;
+                        }
+
+                  color = Flog.RayTracer.Color.prototype.blend(
+                    color,
+                    refl.color,
+                    info.shape.material.reflection
+                  );
+          }
+
+                // Refraction
+                /* TODO */
+            }
+
+            /* Render shadows and highlights */
+
+            var shadowInfo = new Flog.RayTracer.IntersectionInfo();
+
+            if(this.options.renderShadows){
+                var shadowRay = new Flog.RayTracer.Ray(info.position, v);
+
+                shadowInfo = this.testIntersection(shadowRay, scene, info.shape);
+                if(shadowInfo.isHit && shadowInfo.shape != info.shape /*&& shadowInfo.shape.type != 'PLANE'*/){
+                    var vA = Flog.RayTracer.Color.prototype.multiplyScalar(color, 0.5);
+                    var dB = (0.5 * Math.pow(shadowInfo.shape.material.transparency, 0.5));
+                    color = Flog.RayTracer.Color.prototype.addScalar(vA,dB);
+                }
+            }
+
+      // Phong specular highlights
+      if(this.options.renderHighlights && !shadowInfo.isHit && info.shape.material.gloss > 0){
+        var Lv = Flog.RayTracer.Vector.prototype.subtract(
+                            info.shape.position,
+                            light.position
+                        ).normalize();
+
+        var E = Flog.RayTracer.Vector.prototype.subtract(
+                            scene.camera.position,
+                            info.shape.position
+                        ).normalize();
+
+        var H = Flog.RayTracer.Vector.prototype.subtract(
+                            E,
+                            Lv
+                        ).normalize();
+
+        var glossWeight = Math.pow(Math.max(info.normal.dot(H), 0), shininess);
+        color = Flog.RayTracer.Color.prototype.add(
+                            Flog.RayTracer.Color.prototype.multiplyScalar(light.color, glossWeight),
+                            color
+                        );
+      }
+        }
+        color.limit();
+        return color;
+    }
+};
+
+
+function renderScene(){
+    var scene = new Flog.RayTracer.Scene();
+
+    scene.camera = new Flog.RayTracer.Camera(
+                        new Flog.RayTracer.Vector(0, 0, -15),
+                        new Flog.RayTracer.Vector(-0.2, 0, 5),
+                        new Flog.RayTracer.Vector(0, 1, 0)
+                    );
+
+    scene.background = "" Flog.RayTracer.Background(
+                                new Flog.RayTracer.Color(0.5, 0.5, 0.5),
+                                0.4
+                            );
+
+    var sphere = new Flog.RayTracer.Shape.Sphere(
+        new Flog.RayTracer.Vector(-1.5, 1.5, 2),
+        1.5,
+        new Flog.RayTracer.Material.Solid(
+            new Flog.RayTracer.Color(0,0.5,0.5),
+            0.3,
+            0.0,
+            0.0,
+            2.0
+        )
+    );
+
+    var sphere1 = new Flog.RayTracer.Shape.Sphere(
+        new Flog.RayTracer.Vector(1, 0.25, 1),
+        0.5,
+        new Flog.RayTracer.Material.Solid(
+            new Flog.RayTracer.Color(0.9,0.9,0.9),
+            0.1,
+            0.0,
+            0.0,
+            1.5
+        )
+    );
+
+    var plane = new Flog.RayTracer.Shape.Plane(
+                                new Flog.RayTracer.Vector(0.1, 0.9, -0.5).normalize(),
+                                1.2,
+                                new Flog.RayTracer.Material.Chessboard(
+                                    new Flog.RayTracer.Color(1,1,1),
+                                    new Flog.RayTracer.Color(0,0,0),
+                                    0.2,
+                                    0.0,
+                                    1.0,
+                                    0.7
+                                )
+                            );
+
+    scene.shapes.push(plane);
+    scene.shapes.push(sphere);
+    scene.shapes.push(sphere1);
+
+    var light = new Flog.RayTracer.Light(
+        new Flog.RayTracer.Vector(5, 10, -1),
+        new Flog.RayTracer.Color(0.8, 0.8, 0.8)
+    );
+
+    var light1 = new Flog.RayTracer.Light(
+        new Flog.RayTracer.Vector(-3, 5, -15),
+        new Flog.RayTracer.Color(0.8, 0.8, 0.8),
+        100
+    );
+
+    scene.lights.push(light);
+    scene.lights.push(light1);
+
+    var imageWidth = 100; // $F('imageWidth');
+    var imageHeight = 100; // $F('imageHeight');
+    var pixelSize = "5,5".split(','); //  $F('pixelSize').split(',');
+    var renderDiffuse = true; // $F('renderDiffuse');
+    var renderShadows = true; // $F('renderShadows');
+    var renderHighlights = true; // $F('renderHighlights');
+    var renderReflections = true; // $F('renderReflections');
+    var rayDepth = 2;//$F('rayDepth');
+
+    var raytracer = new Flog.RayTracer.Engine(
+        {
+            canvasWidth: imageWidth,
+            canvasHeight: imageHeight,
+            pixelWidth: pixelSize[0],
+            pixelHeight: pixelSize[1],
+            "renderDiffuse": renderDiffuse,
+            "renderHighlights": renderHighlights,
+            "renderShadows": renderShadows,
+            "renderReflections": renderReflections,
+            "rayDepth": rayDepth
+        }
+    );
+
+    raytracer.renderScene(scene, null, 0);
+}
+
+for (var i = 0; i < 6; ++i)
+  renderScene();
Property changes on: trunk/Source/_javascript_Core/tests/executableAllocationFuzz/v8-raytrace.js
___________________________________________________________________

Added: allow-tabs

Added: trunk/Source/_javascript_Core/tests/executableAllocationFuzz.yaml (0 => 181990)


--- trunk/Source/_javascript_Core/tests/executableAllocationFuzz.yaml	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/executableAllocationFuzz.yaml	2015-03-26 01:26:56 UTC (rev 181990)
@@ -0,0 +1,31 @@
+# Copyright (C) 2015 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer. 
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution. 
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+- path: executableAllocationFuzz
+  cmd: |
+      if ($hostOS == "windows")
+          skip
+      else
+          runExecutableAllocationFuzz("default")
+          runExecutableAllocationFuzz("no-cjit", "--enableConcurrentJIT=false")
+      end

Modified: trunk/Tools/ChangeLog (181989 => 181990)


--- trunk/Tools/ChangeLog	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Tools/ChangeLog	2015-03-26 01:26:56 UTC (rev 181990)
@@ -1,3 +1,18 @@
+2015-03-25  Filip Pizlo  <[email protected]>
+
+        Use JITCompilationCanFail in more places, and make the fail path of JITCompilationMustSucceed a crash instead of attempting GC
+        https://bugs.webkit.org/show_bug.cgi?id=142993
+
+        Reviewed by Mark Lam.
+        
+        Bunch of support for testing executable allocation failure.
+
+        * Scripts/jsc-stress-test-helpers/js-executable-allocation-fuzz: Added.
+        (fail):
+        * Scripts/run-_javascript_core-tests:
+        (runJSCStressTests):
+        * Scripts/run-jsc-stress-tests:
+
 2015-03-25  Myles C. Maxfield  <[email protected]>
 
         Fix Windows build from r181977.

Added: trunk/Tools/Scripts/jsc-stress-test-helpers/js-executable-allocation-fuzz (0 => 181990)


--- trunk/Tools/Scripts/jsc-stress-test-helpers/js-executable-allocation-fuzz	                        (rev 0)
+++ trunk/Tools/Scripts/jsc-stress-test-helpers/js-executable-allocation-fuzz	2015-03-26 01:26:56 UTC (rev 181990)
@@ -0,0 +1,126 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer. 
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution. 
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use FindBin;
+use Getopt::Long qw(:config pass_through);
+use POSIX;
+
+# We first want to run the test once to determine what the number of encountered
+# checks is. Then we want to run it again some number of times with random check
+# amounts. The test is successful if it doesn't crash.
+
+my $repeat = 20;
+my $seed = time();
+my $verbose = 0;
+
+# We allow flags to be passed via environment variables, which is rather useful for
+# running with the run-jsc-stress-tests harness.
+if (defined($ENV{JS_EAFUZZ_REPEAT})) {
+    $repeat = $ENV{JS_EAFUZZ_REPEAT};
+}
+if (defined($ENV{JS_EAFUZZ_SEED})) {
+    $seed = $ENV{JS_EAFUZZ_SEED};
+}
+if (defined($ENV{JS_EAFUZZ_VERBOSE})) {
+    $verbose = $ENV{JS_EAFUZZ_VERBOSE};
+}
+
+GetOptions(
+    'repeat=s' => \$repeat,
+    'seed=s' => \$seed,
+    'verbose' => \$verbose
+);
+
+my $commandString = shift @ARGV;
+
+my $checkCount;
+
+sub fail {
+    my $context = shift;
+    select((select(STDOUT), $ |= 1)[0]); # This is a perlism for flush. We need to do it this way to support older perls.
+    select((select(STDERR), $ |= 1)[0]);
+    die "Failure for command $commandString with seed $seed, repeat $repeat: $context";
+}
+
+if (shift @ARGV) {
+    die "Ignoring garbage arguments; only the first non-option argument is used as the command string.";
+}
+
+open (my $testInput, "$commandString --enableExecutableAllocationFuzz=true |") or fail("Cannot execute initial command when getting check count");
+while (my $inputLine = <$testInput>) {
+    chomp($inputLine);
+    my $handled = 0;
+    if ($inputLine =~ /JSC EXECUTABLE ALLOCATION FUZZ: encountered ([0-9]+) checks\./) {
+        $checkCount = $1;
+        $handled = 1;
+    }
+    if (!$handled || $verbose) {
+        print "checkCount: $inputLine\n";
+    }
+}
+close($testInput);
+
+if ($verbose) {
+    print "Check count: $checkCount\n";
+    print "Seed: $seed\n";
+}
+
+if (!$checkCount) {
+    print "Executable allocation fuzz testing not supported by jsc binary.\n";
+    exit 0;
+}
+
+# First do some tests where we have one-off failures.
+srand($seed);
+
+for (my $iteration = 0; $iteration < $repeat; ++$iteration) {
+    my $target = int(rand() * $checkCount) + 1;
+    if ($verbose) {
+        print "iteration($iteration) target($target) one-shot: Running.\n";
+    }
+    my $result = system("$commandString --enableExecutableAllocationFuzz=true --fireExecutableAllocationFuzzAt=$target");
+    if ($result != 0) {
+        fail("Cannot execute command on iteration $iteration, status $? for target $target");
+    }
+}
+
+# Then do some tests where we start failing at a particular point, and then permafail.
+srand($seed);
+
+for (my $iteration = 0; $iteration < $repeat; ++$iteration) {
+    my $target = int(rand() * $checkCount) + 1;
+    if ($verbose) {
+        print "iteration($iteration) target($target) at-or-after: Running.\n";
+    }
+    my $result = system("$commandString --enableExecutableAllocationFuzz=true --fireExecutableAllocationFuzzAtOrAfter=$target");
+    if ($result != 0) {
+        fail("Cannot execute command on iteration $iteration, status $? for target $target");
+    }
+}
+
+if ($verbose) {
+    print "Success!\n";
+}
Property changes on: trunk/Tools/Scripts/jsc-stress-test-helpers/js-executable-allocation-fuzz
___________________________________________________________________

Added: svn:executable

Modified: trunk/Tools/Scripts/run-_javascript_core-tests (181989 => 181990)


--- trunk/Tools/Scripts/run-_javascript_core-tests	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Tools/Scripts/run-_javascript_core-tests	2015-03-26 01:26:56 UTC (rev 181990)
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 
-# Copyright (C) 2005, 2013-2014 Apple Inc.  All rights reserved.
+# Copyright (C) 2005, 2013-2015 Apple Inc.  All rights reserved.
 # Copyright (C) 2007 Eric Seidel <[email protected]>
 #
 # Redistribution and use in source and binary forms, with or without
@@ -269,6 +269,7 @@
         "/usr/bin/env", "ruby", "Tools/Scripts/run-jsc-stress-tests",
         "-j", jscPath($productDir), "-o", $jscStressResultsDir,
         "PerformanceTests/SunSpider/tests/sunspider-1.0",
+        "Source/_javascript_Core/tests/executableAllocationFuzz.yaml",
         "Source/_javascript_Core/tests/exceptionFuzz.yaml",
         "PerformanceTests/SunSpider/no-architecture-specific-optimizations.yaml",
         "PerformanceTests/SunSpider/tests/v8-v6",

Modified: trunk/Tools/Scripts/run-jsc-stress-tests (181989 => 181990)


--- trunk/Tools/Scripts/run-jsc-stress-tests	2015-03-26 01:05:20 UTC (rev 181989)
+++ trunk/Tools/Scripts/run-jsc-stress-tests	2015-03-26 01:26:56 UTC (rev 181990)
@@ -1,6 +1,6 @@
 #!/usr/bin/env ruby
 
-# Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+# Copyright (C) 2013-2015 Apple Inc. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
@@ -781,6 +781,11 @@
     addRunCommand("exception-fuzz", ["perl", (pathToHelpers + "js-exception-fuzz").to_s, subCommand], silentOutputHandler, simpleErrorHandler)
 end
 
+def runExecutableAllocationFuzz(name, *options)
+    subCommand = escapeAll([pathToVM.to_s, $benchmark.to_s] + options)
+    addRunCommand("executable-allocation-fuzz-" + name, ["perl", (pathToHelpers + "js-executable-allocation-fuzz").to_s, subCommand], silentOutputHandler, simpleErrorHandler)
+end
+
 def runTypeProfiler
     if $enableFTL
         run("ftl-no-cjit-type-profiler", "--enableTypeProfiler=true", *(FTL_OPTIONS + NO_CJIT_OPTIONS))
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to