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))