Diff
Modified: branches/jsCStack/Source/_javascript_Core/ChangeLog (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/ChangeLog 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/ChangeLog 2013-12-22 18:42:09 UTC (rev 160980)
@@ -1,3 +1,71 @@
+2013-12-22 Filip Pizlo <[email protected]>
+
+ It should be possible to run the full version of V8v7/crypto with the FTL and call IC's
+ https://bugs.webkit.org/show_bug.cgi?id=126116
+
+ Not yet reviewed.
+
+ This involved a number of minor fixes:
+
+ - CallLinkInfo::unlink() was assuming that repatchBuffer.codeBlock() is the caller.
+ It's actually the callee. So, to determine if the caller requires register
+ preservation, we need an extra bit to say whether the CallLinkInfo belongs to an FTL
+ JITCode.
+
+ - A lot of bugs arise from us incorrectly preserving (or failing to preserve)
+ registers. This adds a bunch of jitAssertTagsInPlace() assertion that helps to catch
+ a bunch of those bugs.
+
+ - Apparently the __compact_unwind sometimes has garbage after its one entry. This
+ changes our unwind parser so that it doesn't assert that the second entry is null,
+ but it does assert that the first entry corresponds to our generated function.
+
+ - The native function thunks assume that tags are set up and that they can clobber any
+ registers. This breaks if we call the thunks from the FTL. This patch fixes the bug
+ by wrapping just those thunks in a DirectJITCode, which has the register preservation
+ wrappers. This probably ends up making sense because the FTL *really* should have
+ intrinsics for all of those thunks. As part of this change, I refactored how
+ NativeExecutable gets its JITCode to make things somewhat more explicit.
+
+ We still have a bunch of known performance bugs to fix, but the FTL is already at near
+ parity with the DFG on V8v7/crypto. This is pretty cool considering the FTL's other
+ speed-ups, and the fact that crypto has been our primary DFG tuning test for the past
+ 2.5 years.
+
+ * bytecode/CallLinkInfo.cpp:
+ (JSC::CallLinkInfo::unlink):
+ * bytecode/CallLinkInfo.h:
+ (JSC::CallLinkInfo::CallLinkInfo):
+ * dfg/DFGJITCompiler.cpp:
+ (JSC::DFG::JITCompiler::compileEntry):
+ * dfg/DFGOSRExitCompiler64.cpp:
+ (JSC::DFG::OSRExitCompiler::compileExit):
+ * dfg/DFGOSRExitCompilerCommon.cpp:
+ (JSC::DFG::adjustAndJumpToTarget):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileCurrentBlock):
+ * ftl/FTLCompile.cpp:
+ (JSC::FTL::compile):
+ * ftl/FTLJSCall.cpp:
+ (JSC::FTL::JSCall::link):
+ * ftl/FTLUnwindInfo.cpp:
+ (JSC::FTL::UnwindInfo::parse):
+ * ftl/FTLUnwindInfo.h:
+ * jit/AssemblyHelpers.cpp:
+ (JSC::AssemblyHelpers::jitAssertTagsInPlace):
+ * jit/AssemblyHelpers.h:
+ (JSC::AssemblyHelpers::jitAssertTagsInPlace):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileMainPass):
+ * jit/JITCode.cpp:
+ * jit/JITCode.h:
+ * jit/JITThunks.cpp:
+ (JSC::JITThunks::hostFunctionStub):
+ * jit/RegisterPreservationWrapperGenerator.cpp:
+ (JSC::generateRegisterPreservationWrapper):
+ * runtime/Executable.h:
+ (JSC::NativeExecutable::create):
+
2013-12-21 Mark Lam <[email protected]>
CStack: Update the VMEntryScope's stack limit when the VM enters/exits ErrorMode.
Modified: branches/jsCStack/Source/_javascript_Core/bytecode/CallLinkInfo.cpp (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/bytecode/CallLinkInfo.cpp 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/bytecode/CallLinkInfo.cpp 2013-12-22 18:42:09 UTC (rev 160980)
@@ -38,14 +38,14 @@
ASSERT(isLinked());
if (Options::showDisassembly())
- dataLog("Unlinking call in ", *repatchBuffer.codeBlock(), " at ", codeOrigin, "\n");
-
+ dataLog("Unlinking call from ", callReturnLocation, " to ", pointerDump(repatchBuffer.codeBlock()), "\n");
+
repatchBuffer.revertJumpReplacementToBranchPtrWithPatch(RepatchBuffer::startOfBranchPtrWithPatchOnRegister(hotPathBegin), static_cast<MacroAssembler::RegisterID>(calleeGPR), 0);
repatchBuffer.relink(
callReturnLocation,
vm.getCTIStub(linkThunkGeneratorFor(
callType == Construct ? CodeForConstruct : CodeForCall,
- repatchBuffer.codeBlock()->jitType() == JITCode::FTLJIT ? MustPreserveRegisters : RegisterPreservationNotRequired)).code());
+ isFTL ? MustPreserveRegisters : RegisterPreservationNotRequired)).code());
hasSeenShouldRepatch = false;
callee.clear();
stub.clear();
Modified: branches/jsCStack/Source/_javascript_Core/bytecode/CallLinkInfo.h (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/bytecode/CallLinkInfo.h 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/bytecode/CallLinkInfo.h 2013-12-22 18:42:09 UTC (rev 160980)
@@ -55,7 +55,8 @@
}
CallLinkInfo()
- : hasSeenShouldRepatch(false)
+ : isFTL(false)
+ , hasSeenShouldRepatch(false)
, hasSeenClosure(false)
, callType(None)
{
@@ -78,6 +79,7 @@
JITWriteBarrier<JSFunction> callee;
WriteBarrier<JSFunction> lastSeenCallee;
RefPtr<ClosureCallStubRoutine> stub;
+ bool isFTL : 1;
bool hasSeenShouldRepatch : 1;
bool hasSeenClosure : 1;
unsigned callType : 5; // CallType
Modified: branches/jsCStack/Source/_javascript_Core/dfg/DFGJITCompiler.cpp (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/dfg/DFGJITCompiler.cpp 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/dfg/DFGJITCompiler.cpp 2013-12-22 18:42:09 UTC (rev 160980)
@@ -100,6 +100,7 @@
// both normal return code and when jumping to an exception handler).
emitFunctionPrologue();
emitPutImmediateToCallFrameHeader(m_codeBlock, JSStack::CodeBlock);
+ jitAssertTagsInPlace();
}
void JITCompiler::compileBody()
Modified: branches/jsCStack/Source/_javascript_Core/dfg/DFGOSRExitCompiler64.cpp (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/dfg/DFGOSRExitCompiler64.cpp 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/dfg/DFGOSRExitCompiler64.cpp 2013-12-22 18:42:09 UTC (rev 160980)
@@ -39,6 +39,8 @@
void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecovery>& operands, SpeculationRecovery* recovery)
{
+ m_jit.jitAssertTagsInPlace();
+
// 1) Pro-forma stuff.
if (Options::printEachOSRExit()) {
SpeculationFailureDebugInfo* debugInfo = new SpeculationFailureDebugInfo;
Modified: branches/jsCStack/Source/_javascript_Core/dfg/DFGOSRExitCompilerCommon.cpp (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/dfg/DFGOSRExitCompilerCommon.cpp 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/dfg/DFGOSRExitCompilerCommon.cpp 2013-12-22 18:42:09 UTC (rev 160980)
@@ -176,6 +176,8 @@
void* jumpTarget = baselineCodeBlock->jitCode()->executableAddressAtOffset(mapping->m_machineCodeOffset);
jit.addPtr(AssemblyHelpers::TrustedImm32(JIT::stackPointerOffsetFor(baselineCodeBlock) * sizeof(Register)), GPRInfo::callFrameRegister, AssemblyHelpers::stackPointerRegister);
+
+ jit.jitAssertTagsInPlace();
jit.move(AssemblyHelpers::TrustedImmPtr(jumpTarget), GPRInfo::regT2);
jit.jump(GPRInfo::regT2);
Modified: branches/jsCStack/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2013-12-22 18:42:09 UTC (rev 160980)
@@ -1466,6 +1466,7 @@
m_stream->appendAndLog(VariableEvent::reset());
m_jit.jitAssertHasValidCallFrame();
+ m_jit.jitAssertTagsInPlace();
for (size_t i = 0; i < m_block->variablesAtHead.numberOfArguments(); ++i) {
m_stream->appendAndLog(
Modified: branches/jsCStack/Source/_javascript_Core/ftl/FTLCompile.cpp (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/ftl/FTLCompile.cpp 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/ftl/FTLCompile.cpp 2013-12-22 18:42:09 UTC (rev 160980)
@@ -458,7 +458,8 @@
}
}
- state.jitCode->unwindInfo.parse(state.compactUnwind, state.compactUnwindSize);
+ state.jitCode->unwindInfo.parse(
+ state.compactUnwind, state.compactUnwindSize, state.generatedFunction);
if (DFG::shouldShowDisassembly())
dataLog("Unwind info for ", CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::FTLJIT), ":\n ", state.jitCode->unwindInfo, "\n");
Modified: branches/jsCStack/Source/_javascript_Core/ftl/FTLJSCall.cpp (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/ftl/FTLJSCall.cpp 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/ftl/FTLJSCall.cpp 2013-12-22 18:42:09 UTC (rev 160980)
@@ -72,6 +72,7 @@
linkBuffer.link(
m_slowCall, FunctionPtr(vm.getCTIStub(generator).code().executableAddress()));
+ callInfo.isFTL = true;
callInfo.callType = m_node->op() == DFG::Construct ? CallLinkInfo::Construct : CallLinkInfo::Call;
callInfo.codeOrigin = m_node->codeOrigin;
callInfo.callReturnLocation = linkBuffer.locationOfNearCall(m_slowCall);
Modified: branches/jsCStack/Source/_javascript_Core/ftl/FTLUnwindInfo.cpp (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/ftl/FTLUnwindInfo.cpp 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/ftl/FTLUnwindInfo.cpp 2013-12-22 18:42:09 UTC (rev 160980)
@@ -48,7 +48,7 @@
} // anonymous namespace
-void UnwindInfo::parse(void* section, size_t size)
+void UnwindInfo::parse(void* section, size_t size, GeneratedFunction generatedFunction)
{
m_registers.clear();
@@ -59,7 +59,7 @@
RELEASE_ASSERT(!data->personality); // We don't know how to handle this.
RELEASE_ASSERT(!data->lsda); // We don't know how to handle this.
- RELEASE_ASSERT(size == sizeof(CompactUnwind) || !data[1].function); // There will only be one function.
+ RELEASE_ASSERT(data->function == generatedFunction); // The unwind data better be for our function.
compact_unwind_encoding_t encoding = data->encoding;
RELEASE_ASSERT(!(encoding & UNWIND_IS_NOT_FUNCTION_START));
Modified: branches/jsCStack/Source/_javascript_Core/ftl/FTLUnwindInfo.h (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/ftl/FTLUnwindInfo.h 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/ftl/FTLUnwindInfo.h 2013-12-22 18:42:09 UTC (rev 160980)
@@ -28,6 +28,7 @@
#if ENABLE(FTL_JIT)
+#include "FTLGeneratedFunction.h"
#include "FTLRegisterAtOffset.h"
namespace JSC { namespace FTL {
@@ -36,7 +37,7 @@
UnwindInfo();
~UnwindInfo();
- void parse(void*, size_t);
+ void parse(void*, size_t, GeneratedFunction);
void dump(PrintStream&) const;
Modified: branches/jsCStack/Source/_javascript_Core/jit/AssemblyHelpers.cpp (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/jit/AssemblyHelpers.cpp 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/jit/AssemblyHelpers.cpp 2013-12-22 18:42:09 UTC (rev 160980)
@@ -110,6 +110,17 @@
breakpoint();
checkCell.link(this);
}
+
+void AssemblyHelpers::jitAssertTagsInPlace()
+{
+ Jump ok = branch64(Equal, GPRInfo::tagTypeNumberRegister, TrustedImm64(TagTypeNumber));
+ breakpoint();
+ ok.link(this);
+
+ ok = branch64(Equal, GPRInfo::tagMaskRegister, TrustedImm64(TagMask));
+ breakpoint();
+ ok.link(this);
+}
#elif USE(JSVALUE32_64)
void AssemblyHelpers::jitAssertIsInt32(GPRReg gpr)
{
@@ -145,6 +156,10 @@
breakpoint();
checkCell.link(this);
}
+
+void AssemblyHelpers::jitAssertTagsInPlace()
+{
+}
#endif // USE(JSVALUE32_64)
void AssemblyHelpers::jitAssertHasValidCallFrame()
Modified: branches/jsCStack/Source/_javascript_Core/jit/AssemblyHelpers.h (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/jit/AssemblyHelpers.h 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/jit/AssemblyHelpers.h 2013-12-22 18:42:09 UTC (rev 160980)
@@ -343,6 +343,7 @@
void jitAssertIsCell(GPRReg);
void jitAssertHasValidCallFrame();
void jitAssertIsNull(GPRReg);
+ void jitAssertTagsInPlace();
#else
void jitAssertIsInt32(GPRReg) { }
void jitAssertIsJSInt32(GPRReg) { }
@@ -351,6 +352,7 @@
void jitAssertIsCell(GPRReg) { }
void jitAssertHasValidCallFrame() { }
void jitAssertIsNull(GPRReg) { }
+ void jitAssertTagsInPlace() { }
#endif
// These methods convert between doubles, and doubles boxed and JSValues.
Modified: branches/jsCStack/Source/_javascript_Core/jit/JIT.cpp (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/jit/JIT.cpp 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/jit/JIT.cpp 2013-12-22 18:42:09 UTC (rev 160980)
@@ -134,6 +134,8 @@
void JIT::privateCompileMainPass()
{
+ jitAssertTagsInPlace();
+
Instruction* instructionsBegin = m_codeBlock->instructions().begin();
unsigned instructionCount = m_codeBlock->instructions().size();
Modified: branches/jsCStack/Source/_javascript_Core/jit/JITCode.cpp (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/jit/JITCode.cpp 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/jit/JITCode.cpp 2013-12-22 18:42:09 UTC (rev 160980)
@@ -72,11 +72,6 @@
return 0;
}
-PassRefPtr<JITCode> JITCode::hostFunction(JITCode::CodeRef code)
-{
- return adoptRef(new NativeJITCode(code, HostCallThunk));
-}
-
JITCodeWithCodeRef::JITCodeWithCodeRef(JITType jitType)
: JITCode(jitType)
{
Modified: branches/jsCStack/Source/_javascript_Core/jit/JITCode.h (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/jit/JITCode.h 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/jit/JITCode.h 2013-12-22 18:42:09 UTC (rev 160980)
@@ -183,8 +183,6 @@
virtual bool contains(void*) = 0;
- static PassRefPtr<JITCode> hostFunction(CodeRef);
-
private:
JITType m_jitType;
};
Modified: branches/jsCStack/Source/_javascript_Core/jit/JITThunks.cpp (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/jit/JITThunks.cpp 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/jit/JITThunks.cpp 2013-12-22 18:42:09 UTC (rev 160980)
@@ -87,7 +87,12 @@
if (NativeExecutable* nativeExecutable = m_hostFunctionStubMap->get(std::make_pair(function, constructor)))
return nativeExecutable;
- NativeExecutable* nativeExecutable = NativeExecutable::create(*vm, JIT::compileCTINativeCall(vm, function), function, MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct(vm)), constructor, NoIntrinsic);
+ NativeExecutable* nativeExecutable = NativeExecutable::create(
+ *vm,
+ adoptRef(new NativeJITCode(JIT::compileCTINativeCall(vm, function), JITCode::HostCallThunk)),
+ function,
+ adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct(vm)), JITCode::HostCallThunk)),
+ constructor, NoIntrinsic);
weakAdd(*m_hostFunctionStubMap, std::make_pair(function, constructor), Weak<NativeExecutable>(nativeExecutable));
return nativeExecutable;
}
@@ -99,16 +104,18 @@
if (NativeExecutable* nativeExecutable = m_hostFunctionStubMap->get(std::make_pair(function, &callHostFunctionAsConstructor)))
return nativeExecutable;
- MacroAssemblerCodeRef code;
+ RefPtr<JITCode> forCall;
if (generator) {
- if (vm->canUseJIT())
- code = generator(vm);
- else
- code = MacroAssemblerCodeRef();
+ if (vm->canUseJIT()) {
+ MacroAssemblerCodeRef entry = generator(vm);
+ forCall = adoptRef(new DirectJITCode(entry, entry.code(), JITCode::HostCallThunk));
+ }
} else
- code = JIT::compileCTINativeCall(vm, function);
-
- NativeExecutable* nativeExecutable = NativeExecutable::create(*vm, code, function, MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct(vm)), callHostFunctionAsConstructor, intrinsic);
+ forCall = adoptRef(new NativeJITCode(JIT::compileCTINativeCall(vm, function), JITCode::HostCallThunk));
+
+ RefPtr<JITCode> forConstruct = adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct(vm)), JITCode::HostCallThunk));
+
+ NativeExecutable* nativeExecutable = NativeExecutable::create(*vm, forCall, function, forConstruct, callHostFunctionAsConstructor, intrinsic);
weakAdd(*m_hostFunctionStubMap, std::make_pair(function, &callHostFunctionAsConstructor), Weak<NativeExecutable>(nativeExecutable));
return nativeExecutable;
}
Modified: branches/jsCStack/Source/_javascript_Core/jit/RegisterPreservationWrapperGenerator.cpp (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/jit/RegisterPreservationWrapperGenerator.cpp 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/jit/RegisterPreservationWrapperGenerator.cpp 2013-12-22 18:42:09 UTC (rev 160980)
@@ -62,8 +62,6 @@
{
#if ENABLE(FTL_JIT)
// We shouldn't ever be generating wrappers for native functions.
- ScriptExecutable* scriptExecutable = jsCast<ScriptExecutable*>(executable);
-
RegisterSet toSave = registersToPreserve();
ptrdiff_t offset = registerPreservationOffset();
@@ -119,7 +117,7 @@
LinkBuffer linkBuffer(vm, &jit, GLOBAL_THUNK_ID);
linkBuffer.link(call, CodeLocationLabel(target));
- return FINALIZE_DFG_CODE(linkBuffer, ("Register preservation wrapper for %s/%s, %p", toCString(scriptExecutable->hashFor(CodeForCall)).data(), toCString(scriptExecutable->hashFor(CodeForConstruct)).data(), target.executableAddress()));
+ return FINALIZE_DFG_CODE(linkBuffer, ("Register preservation wrapper for %s/%s, %p", toCString(executable->hashFor(CodeForCall)).data(), toCString(executable->hashFor(CodeForConstruct)).data(), target.executableAddress()));
#else // ENABLE(FTL_JIT)
UNUSED_PARAM(vm);
UNUSED_PARAM(executable);
Modified: branches/jsCStack/Source/_javascript_Core/runtime/Executable.h (160979 => 160980)
--- branches/jsCStack/Source/_javascript_Core/runtime/Executable.h 2013-12-22 18:15:41 UTC (rev 160979)
+++ branches/jsCStack/Source/_javascript_Core/runtime/Executable.h 2013-12-22 18:42:09 UTC (rev 160980)
@@ -288,14 +288,11 @@
public:
typedef ExecutableBase Base;
- static NativeExecutable* create(VM& vm, MacroAssemblerCodeRef callThunk, NativeFunction function, MacroAssemblerCodeRef constructThunk, NativeFunction constructor, Intrinsic intrinsic)
+ static NativeExecutable* create(VM& vm, PassRefPtr<JITCode> callThunk, NativeFunction function, PassRefPtr<JITCode> constructThunk, NativeFunction constructor, Intrinsic intrinsic)
{
NativeExecutable* executable;
executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor);
- if (!callThunk)
- executable->finishCreation(vm, 0, 0, intrinsic);
- else
- executable->finishCreation(vm, JITCode::hostFunction(callThunk), JITCode::hostFunction(constructThunk), intrinsic);
+ executable->finishCreation(vm, callThunk, constructThunk, intrinsic);
return executable;
}