summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/bytecode/CallLinkInfo.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/JavaScriptCore/bytecode/CallLinkInfo.cpp')
-rw-r--r--Source/JavaScriptCore/bytecode/CallLinkInfo.cpp249
1 files changed, 231 insertions, 18 deletions
diff --git a/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp b/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp
index a4baa6100..7ffda05f4 100644
--- a/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp
+++ b/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2014, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,35 +26,248 @@
#include "config.h"
#include "CallLinkInfo.h"
+#include "CallFrameShuffleData.h"
#include "DFGOperations.h"
#include "DFGThunks.h"
-#include "RepatchBuffer.h"
+#include "FunctionCodeBlock.h"
+#include "JSCInlines.h"
+#include "MacroAssembler.h"
+#include "Opcode.h"
+#include "Repatch.h"
+#include <wtf/ListDump.h>
#if ENABLE(JIT)
namespace JSC {
-void CallLinkInfo::unlink(VM& vm, RepatchBuffer& repatchBuffer)
+CallLinkInfo::CallType CallLinkInfo::callTypeFor(OpcodeID opcodeID)
{
- ASSERT(isLinked());
+ if (opcodeID == op_call || opcodeID == op_call_eval)
+ return Call;
+ if (opcodeID == op_call_varargs)
+ return CallVarargs;
+ if (opcodeID == op_construct)
+ return Construct;
+ if (opcodeID == op_construct_varargs)
+ return ConstructVarargs;
+ if (opcodeID == op_tail_call)
+ return TailCall;
+ ASSERT(opcodeID == op_tail_call_varargs || op_tail_call_forward_arguments);
+ return TailCallVarargs;
+}
+
+CallLinkInfo::CallLinkInfo()
+ : m_hasSeenShouldRepatch(false)
+ , m_hasSeenClosure(false)
+ , m_clearedByGC(false)
+ , m_allowStubs(true)
+ , m_isLinked(false)
+ , m_callType(None)
+ , m_calleeGPR(255)
+ , m_maxNumArguments(0)
+ , m_slowPathCount(0)
+{
+}
+
+CallLinkInfo::~CallLinkInfo()
+{
+ clearStub();
- repatchBuffer.revertJumpReplacementToBranchPtrWithPatch(RepatchBuffer::startOfBranchPtrWithPatchOnRegister(hotPathBegin), static_cast<MacroAssembler::RegisterID>(calleeGPR), 0);
- if (isDFG) {
-#if ENABLE(DFG_JIT)
- repatchBuffer.relink(callReturnLocation, (callType == Construct ? vm.getCTIStub(linkConstructThunkGenerator) : vm.getCTIStub(linkCallThunkGenerator)).code());
-#else
- RELEASE_ASSERT_NOT_REACHED();
-#endif
- } else
- repatchBuffer.relink(callReturnLocation, callType == Construct ? vm.getCTIStub(linkConstructThunkGenerator).code() : vm.getCTIStub(linkCallThunkGenerator).code());
- hasSeenShouldRepatch = false;
- callee.clear();
- stub.clear();
-
- // It will be on a list if the callee has a code block.
if (isOnList())
remove();
}
+void CallLinkInfo::clearStub()
+{
+ if (!stub())
+ return;
+
+ m_stub->clearCallNodesFor(this);
+ m_stub = nullptr;
+}
+
+void CallLinkInfo::unlink(VM& vm)
+{
+ // We could be called even if we're not linked anymore because of how polymorphic calls
+ // work. Each callsite within the polymorphic call stub may separately ask us to unlink().
+ if (isLinked())
+ unlinkFor(vm, *this);
+
+ // Either we were unlinked, in which case we should not have been on any list, or we unlinked
+ // ourselves so that we're not on any list anymore.
+ RELEASE_ASSERT(!isOnList());
+}
+
+CodeLocationNearCall CallLinkInfo::callReturnLocation()
+{
+ RELEASE_ASSERT(!isDirect());
+ return CodeLocationNearCall(m_callReturnLocationOrPatchableJump, Regular);
+}
+
+CodeLocationJump CallLinkInfo::patchableJump()
+{
+ RELEASE_ASSERT(callType() == DirectTailCall);
+ return CodeLocationJump(m_callReturnLocationOrPatchableJump);
+}
+
+CodeLocationDataLabelPtr CallLinkInfo::hotPathBegin()
+{
+ RELEASE_ASSERT(!isDirect());
+ return CodeLocationDataLabelPtr(m_hotPathBeginOrSlowPathStart);
+}
+
+CodeLocationLabel CallLinkInfo::slowPathStart()
+{
+ RELEASE_ASSERT(isDirect());
+ return m_hotPathBeginOrSlowPathStart;
+}
+
+void CallLinkInfo::setCallee(VM& vm, JSCell* owner, JSFunction* callee)
+{
+ RELEASE_ASSERT(!isDirect());
+ MacroAssembler::repatchPointer(hotPathBegin(), callee);
+ m_calleeOrCodeBlock.set(vm, owner, callee);
+ m_isLinked = true;
+}
+
+void CallLinkInfo::clearCallee()
+{
+ RELEASE_ASSERT(!isDirect());
+ MacroAssembler::repatchPointer(hotPathBegin(), nullptr);
+ m_calleeOrCodeBlock.clear();
+ m_isLinked = false;
+}
+
+JSFunction* CallLinkInfo::callee()
+{
+ RELEASE_ASSERT(!isDirect());
+ return jsCast<JSFunction*>(m_calleeOrCodeBlock.get());
+}
+
+void CallLinkInfo::setCodeBlock(VM& vm, JSCell* owner, FunctionCodeBlock* codeBlock)
+{
+ RELEASE_ASSERT(isDirect());
+ m_calleeOrCodeBlock.setMayBeNull(vm, owner, codeBlock);
+ m_isLinked = true;
+}
+
+void CallLinkInfo::clearCodeBlock()
+{
+ RELEASE_ASSERT(isDirect());
+ m_calleeOrCodeBlock.clear();
+ m_isLinked = false;
+}
+
+FunctionCodeBlock* CallLinkInfo::codeBlock()
+{
+ RELEASE_ASSERT(isDirect());
+ return jsCast<FunctionCodeBlock*>(m_calleeOrCodeBlock.get());
+}
+
+void CallLinkInfo::setLastSeenCallee(VM& vm, const JSCell* owner, JSFunction* callee)
+{
+ RELEASE_ASSERT(!isDirect());
+ m_lastSeenCalleeOrExecutable.set(vm, owner, callee);
+}
+
+void CallLinkInfo::clearLastSeenCallee()
+{
+ RELEASE_ASSERT(!isDirect());
+ m_lastSeenCalleeOrExecutable.clear();
+}
+
+JSFunction* CallLinkInfo::lastSeenCallee()
+{
+ RELEASE_ASSERT(!isDirect());
+ return jsCast<JSFunction*>(m_lastSeenCalleeOrExecutable.get());
+}
+
+bool CallLinkInfo::haveLastSeenCallee()
+{
+ RELEASE_ASSERT(!isDirect());
+ return !!m_lastSeenCalleeOrExecutable;
+}
+
+void CallLinkInfo::setExecutableDuringCompilation(ExecutableBase* executable)
+{
+ RELEASE_ASSERT(isDirect());
+ m_lastSeenCalleeOrExecutable.setWithoutWriteBarrier(executable);
+}
+
+ExecutableBase* CallLinkInfo::executable()
+{
+ RELEASE_ASSERT(isDirect());
+ return jsCast<ExecutableBase*>(m_lastSeenCalleeOrExecutable.get());
+}
+
+void CallLinkInfo::setMaxNumArguments(unsigned value)
+{
+ RELEASE_ASSERT(isDirect());
+ RELEASE_ASSERT(value);
+ m_maxNumArguments = value;
+}
+
+void CallLinkInfo::visitWeak(VM& vm)
+{
+ auto handleSpecificCallee = [&] (JSFunction* callee) {
+ if (Heap::isMarked(callee->executable()))
+ m_hasSeenClosure = true;
+ else
+ m_clearedByGC = true;
+ };
+
+ if (isLinked()) {
+ if (stub()) {
+ if (!stub()->visitWeak(vm)) {
+ if (Options::verboseOSR()) {
+ dataLog(
+ "Clearing closure call to ",
+ listDump(stub()->variants()), ", stub routine ", RawPointer(stub()),
+ ".\n");
+ }
+ unlink(vm);
+ m_clearedByGC = true;
+ }
+ } else if (!Heap::isMarked(m_calleeOrCodeBlock.get())) {
+ if (isDirect()) {
+ if (Options::verboseOSR()) {
+ dataLog(
+ "Clearing call to ", RawPointer(codeBlock()), " (",
+ pointerDump(codeBlock()), ").\n");
+ }
+ } else {
+ if (Options::verboseOSR()) {
+ dataLog(
+ "Clearing call to ",
+ RawPointer(callee()), " (",
+ callee()->executable()->hashFor(specializationKind()),
+ ").\n");
+ }
+ handleSpecificCallee(callee());
+ }
+ unlink(vm);
+ } else if (isDirect() && !Heap::isMarked(m_lastSeenCalleeOrExecutable.get())) {
+ if (Options::verboseOSR()) {
+ dataLog(
+ "Clearing call to ", RawPointer(executable()),
+ " because the executable is dead.\n");
+ }
+ unlink(vm);
+ // We should only get here once the owning CodeBlock is dying, since the executable must
+ // already be in the owner's weak references.
+ m_lastSeenCalleeOrExecutable.clear();
+ }
+ }
+ if (!isDirect() && haveLastSeenCallee() && !Heap::isMarked(lastSeenCallee())) {
+ handleSpecificCallee(lastSeenCallee());
+ clearLastSeenCallee();
+ }
+}
+
+void CallLinkInfo::setFrameShuffleData(const CallFrameShuffleData& shuffleData)
+{
+ m_frameShuffleData = std::make_unique<CallFrameShuffleData>(shuffleData);
+}
+
} // namespace JSC
#endif // ENABLE(JIT)