FTL should use LLVM intrinsics for OSR exit, watchpoints, inline caches, and stack layout
https://bugs.webkit.org/show_bug.cgi?id=122318
Reviewed by Geoffrey Garen.
This all now works. This patch just updates our implementation to work with LLVM trunk,
and removes all of the old code that tried to do OSR exits and heap accesses without
the benefit of those intrinsics.
In particular:
- StackMaps parsing now uses the new, less compact, but more future-proof, format.
- Remove the ftlUsesStackmaps() option and hard-code ftlUsesStackmaps = true. Remove
all code for ftlUsesStackmaps = false, since that was only there for back when we
didn't have the intrinsics.
- Remove the other experimental OSR options (useLLVMOSRExitIntrinsic,
ftlTrapsOnOSRExit, and FTLOSRExitOmitsMarshalling).
- Remove LowerDFGToLLVM's use of the ExitThunkGenerator since we don't need to generate
the exit thunks until after we parse the stackmaps.
- Remove all of the exit thunk and compiler code for the no-stackmaps case.
* dfg/DFGDriver.cpp:
(JSC::DFG::compileImpl):
* ftl/FTLCompile.cpp:
(JSC::FTL::mmAllocateDataSection):
* ftl/FTLExitThunkGenerator.cpp:
(JSC::FTL::ExitThunkGenerator::emitThunk):
* ftl/FTLIntrinsicRepository.h:
* ftl/FTLLocation.cpp:
(JSC::FTL::Location::forStackmaps):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::LowerDFGToLLVM):
(JSC::FTL::LowerDFGToLLVM::lower):
(JSC::FTL::LowerDFGToLLVM::compileGetById):
(JSC::FTL::LowerDFGToLLVM::compileInvalidationPoint):
(JSC::FTL::LowerDFGToLLVM::appendOSRExit):
(JSC::FTL::LowerDFGToLLVM::emitOSRExitCall):
(JSC::FTL::LowerDFGToLLVM::callStackmap):
(JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode):
* ftl/FTLOSRExitCompilationInfo.h:
(JSC::FTL::OSRExitCompilationInfo::OSRExitCompilationInfo):
* ftl/FTLOSRExitCompiler.cpp:
(JSC::FTL::compileStub):
(JSC::FTL::compileFTLOSRExit):
* ftl/FTLStackMaps.cpp:
(JSC::FTL::StackMaps::Location::parse):
(JSC::FTL::StackMaps::parse):
(WTF::printInternal):
* ftl/FTLStackMaps.h:
* ftl/FTLThunks.cpp:
(JSC::FTL::osrExitGenerationThunkGenerator):
* ftl/FTLThunks.h:
(JSC::FTL::Thunks::getOSRExitGenerationThunk):
* runtime/Options.h:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@158535 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index b3edfa2..d6c2be6 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,64 @@
+2013-11-02 Filip Pizlo <fpizlo@apple.com>
+
+ FTL should use LLVM intrinsics for OSR exit, watchpoints, inline caches, and stack layout
+ https://bugs.webkit.org/show_bug.cgi?id=122318
+
+ Reviewed by Geoffrey Garen.
+
+ This all now works. This patch just updates our implementation to work with LLVM trunk,
+ and removes all of the old code that tried to do OSR exits and heap accesses without
+ the benefit of those intrinsics.
+
+ In particular:
+
+ - StackMaps parsing now uses the new, less compact, but more future-proof, format.
+
+ - Remove the ftlUsesStackmaps() option and hard-code ftlUsesStackmaps = true. Remove
+ all code for ftlUsesStackmaps = false, since that was only there for back when we
+ didn't have the intrinsics.
+
+ - Remove the other experimental OSR options (useLLVMOSRExitIntrinsic,
+ ftlTrapsOnOSRExit, and FTLOSRExitOmitsMarshalling).
+
+ - Remove LowerDFGToLLVM's use of the ExitThunkGenerator since we don't need to generate
+ the exit thunks until after we parse the stackmaps.
+
+ - Remove all of the exit thunk and compiler code for the no-stackmaps case.
+
+ * dfg/DFGDriver.cpp:
+ (JSC::DFG::compileImpl):
+ * ftl/FTLCompile.cpp:
+ (JSC::FTL::mmAllocateDataSection):
+ * ftl/FTLExitThunkGenerator.cpp:
+ (JSC::FTL::ExitThunkGenerator::emitThunk):
+ * ftl/FTLIntrinsicRepository.h:
+ * ftl/FTLLocation.cpp:
+ (JSC::FTL::Location::forStackmaps):
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::LowerDFGToLLVM):
+ (JSC::FTL::LowerDFGToLLVM::lower):
+ (JSC::FTL::LowerDFGToLLVM::compileGetById):
+ (JSC::FTL::LowerDFGToLLVM::compileInvalidationPoint):
+ (JSC::FTL::LowerDFGToLLVM::appendOSRExit):
+ (JSC::FTL::LowerDFGToLLVM::emitOSRExitCall):
+ (JSC::FTL::LowerDFGToLLVM::callStackmap):
+ (JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode):
+ * ftl/FTLOSRExitCompilationInfo.h:
+ (JSC::FTL::OSRExitCompilationInfo::OSRExitCompilationInfo):
+ * ftl/FTLOSRExitCompiler.cpp:
+ (JSC::FTL::compileStub):
+ (JSC::FTL::compileFTLOSRExit):
+ * ftl/FTLStackMaps.cpp:
+ (JSC::FTL::StackMaps::Location::parse):
+ (JSC::FTL::StackMaps::parse):
+ (WTF::printInternal):
+ * ftl/FTLStackMaps.h:
+ * ftl/FTLThunks.cpp:
+ (JSC::FTL::osrExitGenerationThunkGenerator):
+ * ftl/FTLThunks.h:
+ (JSC::FTL::Thunks::getOSRExitGenerationThunk):
+ * runtime/Options.h:
+
2013-11-02 Patrick Gansterer <paroga@webkit.org>
Add missing getHostCallReturnValue() for MSVC ARM
diff --git a/Source/JavaScriptCore/dfg/DFGDriver.cpp b/Source/JavaScriptCore/dfg/DFGDriver.cpp
index 6eeb197..a81f7f2 100644
--- a/Source/JavaScriptCore/dfg/DFGDriver.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDriver.cpp
@@ -85,9 +85,6 @@
vm.getCTIStub(linkClosureCallThunkGenerator);
vm.getCTIStub(virtualCallThunkGenerator);
vm.getCTIStub(virtualConstructThunkGenerator);
-#if ENABLE(FTL_JIT)
- vm.getCTIStub(FTL::osrExitGenerationWithoutStackMapThunkGenerator);
-#endif
RefPtr<Plan> plan = adoptRef(
new Plan(codeBlock, mode, osrEntryBytecodeIndex, mustHandleValues));
diff --git a/Source/JavaScriptCore/ftl/FTLCompile.cpp b/Source/JavaScriptCore/ftl/FTLCompile.cpp
index 0dbc0e7..1fcd6c6 100644
--- a/Source/JavaScriptCore/ftl/FTLCompile.cpp
+++ b/Source/JavaScriptCore/ftl/FTLCompile.cpp
@@ -78,7 +78,7 @@
RefCountedArray<LSectionWord> section(
(size + sizeof(LSectionWord) - 1) / sizeof(LSectionWord));
- if (!strcmp(sectionName, "__js_stackmaps"))
+ if (!strcmp(sectionName, "__llvm_stackmaps"))
state.stackmapsSection = section;
else {
state.jitCode->addDataSection(section);
diff --git a/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.cpp b/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.cpp
index 6037c30..86c8723 100644
--- a/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.cpp
+++ b/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.cpp
@@ -51,10 +51,7 @@
OSRExitCompilationInfo& info = m_state.finalizer->osrExit[index];
info.m_thunkLabel = label();
- if (Options::ftlUsesStackmaps())
- push(TrustedImm32(index));
- else
- move(TrustedImm32(index), GPRInfo::nonArgGPR0);
+ push(TrustedImm32(index));
info.m_thunkJump = patchableJump();
m_didThings = true;
diff --git a/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h b/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h
index 4ddbb0e..b2103fe 100644
--- a/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h
+++ b/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h
@@ -44,8 +44,8 @@
macro(mulWithOverflow64, "llvm.smul.with.overflow.i64", functionType(structType(m_context, int64, boolean), int64, int64)) \
macro(subWithOverflow32, "llvm.ssub.with.overflow.i32", functionType(structType(m_context, int32, boolean), int32, int32)) \
macro(subWithOverflow64, "llvm.ssub.with.overflow.i64", functionType(structType(m_context, int64, boolean), int64, int64)) \
- macro(webkitPatchpointInt64, "llvm.webkit.patchpoint.i64", functionType(int64, int32, int32, ref8, int32, Variadic)) \
- macro(webkitStackmap, "llvm.webkit.stackmap", functionType(voidType, int32, int32, Variadic)) \
+ macro(patchpointInt64, "llvm.experimental.patchpoint.i64", functionType(int64, int32, int32, ref8, int32, Variadic)) \
+ macro(stackmap, "llvm.experimental.stackmap", functionType(voidType, int32, int32, Variadic)) \
macro(trap, "llvm.trap", functionType(voidType)) \
macro(osrExit, "webkit_osr_exit", functionType(voidType, boolean, int32, Variadic))
diff --git a/Source/JavaScriptCore/ftl/FTLLocation.cpp b/Source/JavaScriptCore/ftl/FTLLocation.cpp
index dc2110d..0ecdf7b 100644
--- a/Source/JavaScriptCore/ftl/FTLLocation.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLocation.cpp
@@ -39,9 +39,11 @@
{
switch (location.kind) {
case StackMaps::Location::Unprocessed:
- return Location();
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
case StackMaps::Location::Register:
+ case StackMaps::Location::Direct:
return forRegister(location.dwarfRegNum, location.offset);
case StackMaps::Location::Indirect:
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
index 1f9c4af..9759ccf 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
@@ -32,7 +32,6 @@
#include "DFGAbstractInterpreterInlines.h"
#include "DFGInPlaceAbstractState.h"
#include "FTLAbstractHeapRepository.h"
-#include "FTLExitThunkGenerator.h"
#include "FTLForOSREntryJITCode.h"
#include "FTLFormattedValue.h"
#include "FTLInlineCacheSize.h"
@@ -53,11 +52,6 @@
static int compileCounter;
-static bool generateExitThunks()
-{
- return !Options::useLLVMOSRExitIntrinsic() && !Options::ftlUsesStackmaps();
-}
-
// Using this instead of typeCheck() helps to reduce the load on LLVM, by creating
// significantly less dead code.
#define FTL_TYPE_CHECK(lowValue, highValue, typesPassedThrough, failCondition) do { \
@@ -78,7 +72,6 @@
, m_out(state.context)
, m_valueSources(OperandsLike, state.graph.block(0)->variablesAtHead)
, m_lastSetOperand(VirtualRegister())
- , m_exitThunkGenerator(state)
, m_state(state.graph)
, m_interpreter(state.graph, m_state)
, m_stackmapIDs(0)
@@ -110,8 +103,6 @@
m_out.appendTo(m_prologue);
createPhiVariables();
- m_initialization = appendBasicBlock(m_ftlState.context, m_ftlState.function);
-
m_callFrame = m_out.param(0);
m_tagTypeNumber = m_out.constInt64(TagTypeNumber);
m_tagMask = m_out.constInt64(TagMask);
@@ -123,14 +114,14 @@
m_blocks.add(m_highBlock, FTL_NEW_BLOCK(m_out, ("Block ", *m_highBlock)));
}
+ m_out.appendTo(m_prologue);
+ m_out.jump(lowBlock(m_graph.block(0)));
+
Vector<BasicBlock*> depthFirst;
m_graph.getBlocksInDepthFirstOrder(depthFirst);
for (unsigned i = 0; i < depthFirst.size(); ++i)
compileBlock(depthFirst[i]);
- // And now complete the initialization block.
- linkOSRExitsAndCompleteInitializationBlocks();
-
if (Options::dumpLLVMIR())
dumpModule(m_ftlState.module);
@@ -1258,15 +1249,10 @@
LValue base = lowCell(m_node->child1());
StringImpl* uid = m_graph.identifiers()[m_node->identifierNumber()];
- if (!Options::ftlUsesStackmaps()) {
- setJSValue(vmCall(m_out.operation(operationGetById), m_callFrame, m_out.intPtrZero, base, m_out.constIntPtr(uid)));
- return;
- }
-
// Arguments: id, bytes, target, numArgs, args...
unsigned stackmapID = m_stackmapIDs++;
setJSValue(m_out.call(
- m_out.webkitPatchpointInt64Intrinsic(),
+ m_out.patchpointInt64Intrinsic(),
m_out.constInt32(stackmapID), m_out.constInt32(sizeOfGetById()),
constNull(m_out.ref8), m_out.constInt32(2), m_callFrame, base));
@@ -2136,12 +2122,6 @@
void compileInvalidationPoint()
{
- if (!Options::ftlUsesStackmaps()) {
- // We silently don't implement invalidation points if we don't have stackmaps.
- // This is fine since the long-term plan is to require stackmaps.
- return;
- }
-
if (verboseCompilationEnabled())
dataLog(" Invalidation point with value sources: ", m_valueSources, "\n");
@@ -3309,25 +3289,10 @@
ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition,
SpeculationDirection direction, FormattedValue recovery)
{
- if (Options::ftlTrapsOnOSRExit()) {
- LBasicBlock failCase = FTL_NEW_BLOCK(m_out, ("OSR exit failCase for ", m_node));
- LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("OSR exit continuation for ", m_node));
-
- m_out.branch(failCondition, failCase, continuation);
-
- LBasicBlock lastNext = m_out.appendTo(failCase, continuation);
- m_out.trap();
- m_out.unreachable();
-
- m_out.appendTo(continuation, lastNext);
- return;
- }
-
if (verboseCompilationEnabled())
dataLog(" OSR exit with value sources: ", m_valueSources, "\n");
ASSERT(m_ftlState.jitCode->osrExit.size() == m_ftlState.finalizer->osrExit.size());
- unsigned index = m_ftlState.finalizer->osrExit.size();
m_ftlState.jitCode->osrExit.append(OSRExit(
kind, lowValue.format(), m_graph.methodOfGettingAValueProfileFor(highValue),
@@ -3336,54 +3301,30 @@
m_ftlState.finalizer->osrExit.append(OSRExitCompilationInfo());
OSRExit& exit = m_ftlState.jitCode->osrExit.last();
- OSRExitCompilationInfo& info = m_ftlState.finalizer->osrExit.last();
LBasicBlock lastNext = 0;
LBasicBlock continuation = 0;
- if (!Options::useLLVMOSRExitIntrinsic()) {
- LBasicBlock failCase = FTL_NEW_BLOCK(m_out, ("OSR exit failCase for ", m_node));
- continuation = FTL_NEW_BLOCK(m_out, ("OSR exit continuation for ", m_node));
-
- m_out.branch(failCondition, failCase, continuation);
-
- if (generateExitThunks()) {
- m_out.appendTo(m_prologue);
- info.m_thunkAddressValue = buildAlloca(m_out.m_builder, m_out.intPtr);
- }
+ LBasicBlock failCase = FTL_NEW_BLOCK(m_out, ("OSR exit failCase for ", m_node));
+ continuation = FTL_NEW_BLOCK(m_out, ("OSR exit continuation for ", m_node));
- lastNext = m_out.appendTo(failCase, continuation);
- }
+ m_out.branch(failCondition, failCase, continuation);
- if (Options::ftlOSRExitOmitsMarshalling()) {
- m_out.call(
- m_out.intToPtr(
- m_out.get(info.m_thunkAddressValue),
- pointerType(functionType(m_out.voidType))));
- } else
- emitOSRExitCall(failCondition, index, exit, info, lowValue, direction, recovery);
+ lastNext = m_out.appendTo(failCase, continuation);
- if (!Options::useLLVMOSRExitIntrinsic()) {
- m_out.unreachable();
-
- m_out.appendTo(continuation, lastNext);
+ emitOSRExitCall(exit, lowValue, direction, recovery);
- if (generateExitThunks())
- m_exitThunkGenerator.emitThunk(index);
- }
+ m_out.unreachable();
+
+ m_out.appendTo(continuation, lastNext);
}
void emitOSRExitCall(
- LValue failCondition, unsigned index, OSRExit& exit, OSRExitCompilationInfo& info,
- FormattedValue lowValue, SpeculationDirection direction, FormattedValue recovery)
+ OSRExit& exit, FormattedValue lowValue, SpeculationDirection direction,
+ FormattedValue recovery)
{
ExitArgumentList arguments;
- if (Options::useLLVMOSRExitIntrinsic()) {
- arguments.append(failCondition);
- arguments.append(m_out.constInt32(index));
- }
-
buildExitArguments(exit, arguments, lowValue);
if (direction == ForwardSpeculation) {
@@ -3391,27 +3332,7 @@
exit.convertToForward(m_highBlock, m_node, m_nodeIndex, recovery, arguments);
}
- if (Options::useLLVMOSRExitIntrinsic()) {
- m_out.call(m_out.osrExitIntrinsic(), arguments);
- return;
- }
-
- if (Options::ftlUsesStackmaps()) {
- callStackmap(exit, arguments);
- return;
- }
-
- // So, the really lame thing here is that we have to build an LLVM function type.
- // Booo.
- Vector<LType, 16> argumentTypes;
- for (unsigned i = 0; i < arguments.size(); ++i)
- argumentTypes.append(typeOf(arguments[i]));
-
- m_out.call(
- m_out.intToPtr(
- m_out.get(info.m_thunkAddressValue),
- pointerType(functionType(m_out.voidType, argumentTypes))),
- arguments);
+ callStackmap(exit, arguments);
}
void buildExitArguments(
@@ -3459,7 +3380,7 @@
arguments.insert(0, m_out.constInt32(MacroAssembler::maxJumpReplacementSize()));
arguments.insert(0, m_out.constInt32(exit.m_stackmapID));
- m_out.call(m_out.webkitStackmapIntrinsic(), arguments);
+ m_out.call(m_out.stackmapIntrinsic(), arguments);
}
void addExitArgumentForNode(
@@ -3538,11 +3459,7 @@
value = m_booleanValues.get(node);
if (isValid(value)) {
- LValue valueToPass;
- if (Options::ftlUsesStackmaps())
- valueToPass = m_out.zeroExt(value.value(), m_out.int32);
- else
- valueToPass = value.value();
+ LValue valueToPass = m_out.zeroExt(value.value(), m_out.int32);
addExitArgument(exit, arguments, index, ValueFormatBoolean, valueToPass);
return;
}
@@ -3591,44 +3508,6 @@
arguments.append(value);
}
- void linkOSRExitsAndCompleteInitializationBlocks()
- {
- MacroAssemblerCodeRef osrExitThunk =
- vm().getCTIStub(osrExitGenerationWithoutStackMapThunkGenerator);
- CodeLocationLabel target = CodeLocationLabel(osrExitThunk.code());
-
- m_out.appendTo(m_prologue);
- m_out.jump(m_initialization);
-
- m_out.appendTo(m_initialization);
-
- if (m_exitThunkGenerator.didThings()) {
- OwnPtr<LinkBuffer> linkBuffer = adoptPtr(new LinkBuffer(
- vm(), &m_exitThunkGenerator, m_ftlState.graph.m_codeBlock,
- JITCompilationMustSucceed));
-
- ASSERT(m_ftlState.finalizer->osrExit.size() == m_ftlState.jitCode->osrExit.size());
-
- for (unsigned i = 0; i < m_ftlState.finalizer->osrExit.size(); ++i) {
- OSRExitCompilationInfo& info = m_ftlState.finalizer->osrExit[i];
- OSRExit& exit = m_ftlState.jitCode->osrExit[i];
-
- linkBuffer->link(info.m_thunkJump, target);
-
- m_out.set(
- m_out.constIntPtr(
- linkBuffer->locationOf(info.m_thunkLabel).executableAddress()),
- info.m_thunkAddressValue);
-
- exit.m_patchableCodeOffset = linkBuffer->offsetOf(info.m_thunkJump);
- }
-
- m_ftlState.finalizer->exitThunksLinkBuffer = linkBuffer.release();
- }
-
- m_out.jump(lowBlock(m_graph.block(0)));
- }
-
void observeMovHint(Node* node)
{
ASSERT(node->containsMovHint());
@@ -3782,7 +3661,6 @@
Output m_out;
LBasicBlock m_prologue;
- LBasicBlock m_initialization;
HashMap<BasicBlock*, LBasicBlock> m_blocks;
LValue m_callFrame;
@@ -3802,7 +3680,6 @@
Operands<ValueSource> m_valueSources;
VirtualRegister m_lastSetOperand;
- ExitThunkGenerator m_exitThunkGenerator;
InPlaceAbstractState m_state;
AbstractInterpreter<InPlaceAbstractState> m_interpreter;
diff --git a/Source/JavaScriptCore/ftl/FTLOSRExitCompilationInfo.h b/Source/JavaScriptCore/ftl/FTLOSRExitCompilationInfo.h
index 1facf03..796c9d6 100644
--- a/Source/JavaScriptCore/ftl/FTLOSRExitCompilationInfo.h
+++ b/Source/JavaScriptCore/ftl/FTLOSRExitCompilationInfo.h
@@ -37,15 +37,13 @@
struct OSRExitCompilationInfo {
OSRExitCompilationInfo()
- : m_thunkAddressValue(0)
- , m_isInvalidationPoint(false)
+ : m_isInvalidationPoint(false)
{
}
MacroAssembler::Label m_thunkLabel;
MacroAssembler::PatchableJump m_thunkJump;
CodeLocationLabel m_thunkAddress;
- LValue m_thunkAddressValue;
bool m_isInvalidationPoint;
};
diff --git a/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp b/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp
index 36fba88..4952a41 100644
--- a/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp
+++ b/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp
@@ -42,11 +42,7 @@
using namespace DFG;
-// This implements two flavors of OSR exit: one that involves having LLVM intrinsics to help
-// OSR exit, and one that doesn't. The one that doesn't will get killed off, so we don't attempt
-// to share code between the two.
-
-static void compileStubWithOSRExitStackmap(
+static void compileStub(
unsigned exitID, JITCode* jitCode, OSRExit& exit, VM* vm, CodeBlock* codeBlock)
{
StackMaps::Record* record;
@@ -178,169 +174,6 @@
toCString(*record).data()));
}
-static void compileStubWithoutOSRExitStackmap(
- unsigned exitID, OSRExit& exit, VM* vm, CodeBlock* codeBlock)
-{
- CCallHelpers jit(vm, codeBlock);
-
- // Make ourselves look like a real C function.
- jit.push(MacroAssembler::framePointerRegister);
- jit.move(MacroAssembler::stackPointerRegister, MacroAssembler::framePointerRegister);
-
- // This is actually fairly easy, even though it is horribly gross. We know that
- // LLVM would have passes us all of the state via arguments. We know how to get
- // the arguments. And, we know how to pop stack back to the JIT stack frame, sort
- // of: we know that it's two frames beneath us. This is terrible and I feel
- // ashamed of it, but it will work for now.
-
- CArgumentGetter arguments(jit, 2);
-
- // First recover our call frame and tag thingies.
- arguments.loadNextPtr(GPRInfo::callFrameRegister);
- jit.move(MacroAssembler::TrustedImm64(TagTypeNumber), GPRInfo::tagTypeNumberRegister);
- jit.move(MacroAssembler::TrustedImm64(TagMask), GPRInfo::tagMaskRegister);
-
- // Do some value profiling.
- if (exit.m_profileValueFormat != InvalidValueFormat) {
- arguments.loadNextAndBox(exit.m_profileValueFormat, GPRInfo::nonArgGPR0);
-
- if (exit.m_kind == BadCache || exit.m_kind == BadIndexingType) {
- CodeOrigin codeOrigin = exit.m_codeOriginForExitProfile;
- if (ArrayProfile* arrayProfile = jit.baselineCodeBlockFor(codeOrigin)->getArrayProfile(codeOrigin.bytecodeIndex)) {
- jit.loadPtr(MacroAssembler::Address(GPRInfo::nonArgGPR0, JSCell::structureOffset()), GPRInfo::nonArgGPR1);
- jit.storePtr(GPRInfo::nonArgGPR1, arrayProfile->addressOfLastSeenStructure());
- jit.load8(MacroAssembler::Address(GPRInfo::nonArgGPR1, Structure::indexingTypeOffset()), GPRInfo::nonArgGPR1);
- jit.move(MacroAssembler::TrustedImm32(1), GPRInfo::nonArgGPR2);
- jit.lshift32(GPRInfo::nonArgGPR1, GPRInfo::nonArgGPR2);
- jit.or32(GPRInfo::nonArgGPR2, MacroAssembler::AbsoluteAddress(arrayProfile->addressOfArrayModes()));
- }
- }
-
- if (!!exit.m_valueProfile)
- jit.store64(GPRInfo::nonArgGPR0, exit.m_valueProfile.getSpecFailBucket(0));
- }
-
- // Use a scratch buffer to transfer all values.
- ScratchBuffer* scratchBuffer = vm->scratchBufferForSize(sizeof(EncodedJSValue) * exit.m_values.size());
- EncodedJSValue* scratch = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0;
-
- // Start by dumping all argument exit values to the stack.
-
- Vector<ExitArgumentForOperand, 16> sortedArguments;
- for (unsigned i = exit.m_values.size(); i--;) {
- ExitValue value = exit.m_values[i];
- int operand = exit.m_values.operandForIndex(i);
-
- if (!value.isArgument())
- continue;
-
- sortedArguments.append(ExitArgumentForOperand(value.exitArgument(), VirtualRegister(operand)));
- }
- std::sort(sortedArguments.begin(), sortedArguments.end(), lesserArgumentIndex);
-
- for (unsigned i = 0; i < sortedArguments.size(); ++i) {
- ExitArgumentForOperand argument = sortedArguments[i];
-
- arguments.loadNextAndBox(argument.exitArgument().format(), GPRInfo::nonArgGPR0);
- jit.store64(
- GPRInfo::nonArgGPR0, scratch + exit.m_values.indexForOperand(argument.operand()));
- }
-
- // All temp registers are free at this point.
-
- // Move anything on the stack into the appropriate place in the scratch buffer.
-
- for (unsigned i = exit.m_values.size(); i--;) {
- ExitValue value = exit.m_values[i];
-
- switch (value.kind()) {
- case ExitValueInJSStack:
- jit.load64(AssemblyHelpers::addressFor(value.virtualRegister()), GPRInfo::regT0);
- break;
- case ExitValueInJSStackAsInt32:
- jit.load32(
- AssemblyHelpers::addressFor(value.virtualRegister()).withOffset(
- OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
- GPRInfo::regT0);
- jit.or64(GPRInfo::tagTypeNumberRegister, GPRInfo::regT0);
- break;
- case ExitValueInJSStackAsInt52:
- jit.load64(AssemblyHelpers::addressFor(value.virtualRegister()), GPRInfo::regT0);
- jit.rshift64(
- AssemblyHelpers::TrustedImm32(JSValue::int52ShiftAmount), GPRInfo::regT0);
- jit.boxInt52(GPRInfo::regT0, GPRInfo::regT0, GPRInfo::regT1, FPRInfo::fpRegT0);
- break;
- case ExitValueInJSStackAsDouble:
- jit.loadDouble(AssemblyHelpers::addressFor(value.virtualRegister()), FPRInfo::fpRegT0);
- jit.boxDouble(FPRInfo::fpRegT0, GPRInfo::regT0);
- break;
- case ExitValueDead:
- case ExitValueConstant:
- case ExitValueArgument:
- // Don't do anything for these.
- continue;
- default:
- RELEASE_ASSERT_NOT_REACHED();
- break;
- }
-
- jit.store64(GPRInfo::regT0, scratch + i);
- }
-
- // Move everything from the scratch buffer to the stack; this also reifies constants.
-
- for (unsigned i = exit.m_values.size(); i--;) {
- ExitValue value = exit.m_values[i];
- int operand = exit.m_values.operandForIndex(i);
-
- MacroAssembler::Address address = AssemblyHelpers::addressFor(operand);
-
- switch (value.kind()) {
- case ExitValueDead:
- jit.store64(MacroAssembler::TrustedImm64(JSValue::encode(jsUndefined())), address);
- break;
- case ExitValueConstant:
- jit.store64(MacroAssembler::TrustedImm64(JSValue::encode(value.constant())), address);
- break;
- case ExitValueInJSStack:
- case ExitValueInJSStackAsInt32:
- case ExitValueInJSStackAsInt52:
- case ExitValueInJSStackAsDouble:
- case ExitValueArgument:
- jit.load64(scratch + i, GPRInfo::regT0);
- jit.store64(GPRInfo::regT0, address);
- break;
- default:
- RELEASE_ASSERT_NOT_REACHED();
- break;
- }
- }
-
- handleExitCounts(jit, exit);
- reifyInlinedCallFrames(jit, exit);
-
- jit.pop(MacroAssembler::framePointerRegister);
- jit.move(MacroAssembler::framePointerRegister, MacroAssembler::stackPointerRegister);
- jit.pop(MacroAssembler::framePointerRegister);
- jit.pop(GPRInfo::nonArgGPR0); // ignore the result.
-
- if (exit.m_lastSetOperand.isValid()) {
- jit.load64(
- AssemblyHelpers::addressFor(exit.m_lastSetOperand), GPRInfo::cachedResultRegister);
- }
-
- adjustAndJumpToTarget(jit, exit);
-
- LinkBuffer patchBuffer(*vm, &jit, codeBlock);
- exit.m_code = FINALIZE_CODE_IF(
- shouldShowDisassembly(),
- patchBuffer,
- ("FTL OSR exit #%u (bc#%u, %s) from %s, with operands = %s",
- exitID, exit.m_codeOrigin.bytecodeIndex,
- exitKindToString(exit.m_kind), toCString(*codeBlock).data(),
- toCString(ignoringContext<DumpContext>(exit.m_values)).data()));
-}
-
extern "C" void* compileFTLOSRExit(ExecState* exec, unsigned exitID)
{
SamplingRegion samplingRegion("FTL OSR Exit Compilation");
@@ -361,10 +194,7 @@
prepareCodeOriginForOSRExit(exec, exit.m_codeOrigin);
- if (Options::ftlUsesStackmaps())
- compileStubWithOSRExitStackmap(exitID, jitCode, exit, vm, codeBlock);
- else
- compileStubWithoutOSRExitStackmap(exitID, exit, vm, codeBlock);
+ compileStub(exitID, jitCode, exit, vm, codeBlock);
RepatchBuffer repatchBuffer(codeBlock);
repatchBuffer.relink(
diff --git a/Source/JavaScriptCore/ftl/FTLStackMaps.cpp b/Source/JavaScriptCore/ftl/FTLStackMaps.cpp
index 5862091..f688cb1 100644
--- a/Source/JavaScriptCore/ftl/FTLStackMaps.cpp
+++ b/Source/JavaScriptCore/ftl/FTLStackMaps.cpp
@@ -55,17 +55,10 @@
void StackMaps::Location::parse(DataView* view, unsigned& offset)
{
- uint16_t taggedReg = view->read<uint16_t>(offset, true);
- if (static_cast<int16_t>(taggedReg) < 0) {
- dataLog(
- "Detected a negative tagged register ", static_cast<int16_t>(taggedReg),
- " at offset ", offset, "\n");
- RELEASE_ASSERT_NOT_REACHED();
- }
- dwarfRegNum = taggedReg & ((1 << 12) - 1);
- kind = static_cast<Kind>(taggedReg >> 12);
-
- this->offset = view->read<int16_t>(offset, true);
+ kind = static_cast<Kind>(view->read<uint8_t>(offset, true));
+ view->read<uint8_t>(offset, true); // reserved
+ dwarfRegNum = view->read<uint16_t>(offset, true);
+ this->offset = view->read<int32_t>(offset, true);
}
void StackMaps::Location::dump(PrintStream& out) const
@@ -111,6 +104,8 @@
{
unsigned offset = 0;
+ view->read<uint32_t>(offset, true); // Reserved (header)
+
uint32_t numConstants = view->read<uint32_t>(offset, true);
while (numConstants--)
constants.append(readObject<Constant>(view, offset));
@@ -164,6 +159,9 @@
case StackMaps::Location::Register:
out.print("Register");
return;
+ case StackMaps::Location::Direct:
+ out.print("Direct");
+ return;
case StackMaps::Location::Indirect:
out.print("Indirect");
return;
diff --git a/Source/JavaScriptCore/ftl/FTLStackMaps.h b/Source/JavaScriptCore/ftl/FTLStackMaps.h
index fac5afc..13d1966 100644
--- a/Source/JavaScriptCore/ftl/FTLStackMaps.h
+++ b/Source/JavaScriptCore/ftl/FTLStackMaps.h
@@ -52,6 +52,7 @@
enum Kind {
Unprocessed,
Register,
+ Direct,
Indirect,
Constant,
ConstantIndex
diff --git a/Source/JavaScriptCore/ftl/FTLThunks.cpp b/Source/JavaScriptCore/ftl/FTLThunks.cpp
index 1c7e7dc..bf04af0 100644
--- a/Source/JavaScriptCore/ftl/FTLThunks.cpp
+++ b/Source/JavaScriptCore/ftl/FTLThunks.cpp
@@ -39,60 +39,7 @@
using namespace DFG;
-MacroAssemblerCodeRef osrExitGenerationWithoutStackMapThunkGenerator(VM* vm)
-{
- AssemblyHelpers jit(vm, 0);
-
- // Pretend that we're a C call frame.
- jit.push(MacroAssembler::framePointerRegister);
- jit.move(MacroAssembler::stackPointerRegister, MacroAssembler::framePointerRegister);
- jit.push(GPRInfo::regT0);
- jit.push(GPRInfo::regT0);
-
- jit.poke(GPRInfo::nonArgGPR0, 1);
-
- ScratchBuffer* scratchBuffer = vm->scratchBufferForSize(requiredScratchMemorySizeInBytes());
- char* buffer = static_cast<char*>(scratchBuffer->dataBuffer());
-
- saveAllRegisters(jit, buffer);
-
- // Tell GC mark phase how much of the scratch buffer is active during call.
- jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::nonArgGPR1);
- jit.storePtr(MacroAssembler::TrustedImmPtr(requiredScratchMemorySizeInBytes()), GPRInfo::nonArgGPR1);
-
- // argument 0 is already the call frame.
- jit.peek(GPRInfo::argumentGPR1, 1);
- MacroAssembler::Call functionCall = jit.call();
-
- // At this point we want to make a tail call to what was returned to us in the
- // returnValueGPR. But at the same time as we do this, we must restore all registers.
- // The way we will accomplish this is by arranging to have the tail call target in the
- // return address "slot" (be it a register or the stack).
-
- jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0);
-
- // Prepare for tail call.
- jit.pop(GPRInfo::regT1);
- jit.pop(GPRInfo::regT1);
- jit.pop(MacroAssembler::framePointerRegister);
-
- // At this point we're sitting on the return address - so if we did a jump right now, the
- // tail-callee would be happy. Instead we'll stash the callee in the return address and then
- // restore all registers.
-
- jit.restoreReturnAddressBeforeReturn(GPRInfo::regT0);
-
- restoreAllRegisters(jit, buffer);
-
- jit.ret();
-
- LinkBuffer patchBuffer(*vm, &jit, GLOBAL_THUNK_ID);
- patchBuffer.link(functionCall, compileFTLOSRExit);
- return FINALIZE_CODE(patchBuffer, ("FTL OSR exit generation thunk"));
-}
-
-MacroAssemblerCodeRef osrExitGenerationWithStackMapThunkGenerator(
- VM& vm, const Location& location)
+MacroAssemblerCodeRef osrExitGenerationThunkGenerator(VM& vm, const Location& location)
{
AssemblyHelpers jit(&vm, 0);
diff --git a/Source/JavaScriptCore/ftl/FTLThunks.h b/Source/JavaScriptCore/ftl/FTLThunks.h
index da1cf10..ffa0245 100644
--- a/Source/JavaScriptCore/ftl/FTLThunks.h
+++ b/Source/JavaScriptCore/ftl/FTLThunks.h
@@ -41,9 +41,7 @@
namespace FTL {
-MacroAssemblerCodeRef osrExitGenerationWithoutStackMapThunkGenerator(VM*);
-
-MacroAssemblerCodeRef osrExitGenerationWithStackMapThunkGenerator(VM&, const Location&);
+MacroAssemblerCodeRef osrExitGenerationThunkGenerator(VM&, const Location&);
MacroAssemblerCodeRef slowPathCallThunkGenerator(VM&, const SlowPathCallKey&);
template<typename MapType, typename KeyType, typename GeneratorType>
@@ -64,7 +62,7 @@
MacroAssemblerCodeRef getOSRExitGenerationThunk(VM& vm, const Location& location)
{
return generateIfNecessary(
- vm, m_osrExitThunks, location, osrExitGenerationWithStackMapThunkGenerator);
+ vm, m_osrExitThunks, location, osrExitGenerationThunkGenerator);
}
MacroAssemblerCodeRef getSlowPathCallThunk(VM& vm, const SlowPathCallKey& key)
diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h
index 3d9b43e..2879069 100644
--- a/Source/JavaScriptCore/runtime/Options.h
+++ b/Source/JavaScriptCore/runtime/Options.h
@@ -124,10 +124,6 @@
v(bool, useFTLTBAA, true) \
v(bool, enableLLVMFastISel, false) \
v(bool, useLLVMSmallCodeModel, false) \
- v(bool, ftlTrapsOnOSRExit, false) \
- v(bool, ftlOSRExitOmitsMarshalling, false) \
- v(bool, ftlUsesStackmaps, false) \
- v(bool, useLLVMOSRExitIntrinsic, false) \
v(bool, dumpLLVMIR, false) \
v(bool, llvmAlwaysFailsBeforeCompile, false) \
v(bool, llvmAlwaysFailsBeforeLink, false) \