diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/bytecode/CallLinkInfo.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/bytecode/CallLinkInfo.cpp')
-rw-r--r-- | Source/JavaScriptCore/bytecode/CallLinkInfo.cpp | 249 |
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) |