/* * 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 * 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. */ #pragma once #include "CallMode.h" #include "CodeLocation.h" #include "CodeSpecializationKind.h" #include "PolymorphicCallStubRoutine.h" #include "WriteBarrier.h" #include namespace JSC { #if ENABLE(JIT) class FunctionCodeBlock; class JSFunction; enum OpcodeID : unsigned; struct CallFrameShuffleData; class CallLinkInfo : public BasicRawSentinelNode { public: enum CallType { None, Call, CallVarargs, Construct, ConstructVarargs, TailCall, TailCallVarargs, DirectCall, DirectConstruct, DirectTailCall }; static CallType callTypeFor(OpcodeID opcodeID); static bool isVarargsCallType(CallType callType) { switch (callType) { case CallVarargs: case ConstructVarargs: case TailCallVarargs: return true; default: return false; } } CallLinkInfo(); ~CallLinkInfo(); static CodeSpecializationKind specializationKindFor(CallType callType) { return specializationFromIsConstruct(callType == Construct || callType == ConstructVarargs || callType == DirectConstruct); } CodeSpecializationKind specializationKind() const { return specializationKindFor(static_cast(m_callType)); } static CallMode callModeFor(CallType callType) { switch (callType) { case Call: case CallVarargs: case DirectCall: return CallMode::Regular; case TailCall: case TailCallVarargs: case DirectTailCall: return CallMode::Tail; case Construct: case ConstructVarargs: case DirectConstruct: return CallMode::Construct; case None: RELEASE_ASSERT_NOT_REACHED(); } RELEASE_ASSERT_NOT_REACHED(); } static bool isDirect(CallType callType) { switch (callType) { case DirectCall: case DirectTailCall: case DirectConstruct: return true; case Call: case CallVarargs: case TailCall: case TailCallVarargs: case Construct: case ConstructVarargs: return false; case None: RELEASE_ASSERT_NOT_REACHED(); return false; } RELEASE_ASSERT_NOT_REACHED(); return false; } CallMode callMode() const { return callModeFor(static_cast(m_callType)); } bool isDirect() { return isDirect(static_cast(m_callType)); } bool isTailCall() const { return callMode() == CallMode::Tail; } NearCallMode nearCallMode() const { return isTailCall() ? Tail : Regular; } bool isVarargs() const { return isVarargsCallType(static_cast(m_callType)); } bool isLinked() { return m_stub || m_calleeOrCodeBlock; } void unlink(VM&); void setUpCall(CallType callType, CodeOrigin codeOrigin, unsigned calleeGPR) { m_callType = callType; m_codeOrigin = codeOrigin; m_calleeGPR = calleeGPR; } void setCallLocations( CodeLocationLabel callReturnLocationOrPatchableJump, CodeLocationLabel hotPathBeginOrSlowPathStart, CodeLocationNearCall hotPathOther) { m_callReturnLocationOrPatchableJump = callReturnLocationOrPatchableJump; m_hotPathBeginOrSlowPathStart = hotPathBeginOrSlowPathStart; m_hotPathOther = hotPathOther; } bool allowStubs() const { return m_allowStubs; } void disallowStubs() { m_allowStubs = false; } CodeLocationNearCall callReturnLocation(); CodeLocationJump patchableJump(); CodeLocationDataLabelPtr hotPathBegin(); CodeLocationLabel slowPathStart(); CodeLocationNearCall hotPathOther() { return m_hotPathOther; } void setCallee(VM&, JSCell*, JSFunction* callee); void clearCallee(); JSFunction* callee(); void setCodeBlock(VM&, JSCell*, FunctionCodeBlock*); void clearCodeBlock(); FunctionCodeBlock* codeBlock(); void setLastSeenCallee(VM& vm, const JSCell* owner, JSFunction* callee); void clearLastSeenCallee(); JSFunction* lastSeenCallee(); bool haveLastSeenCallee(); void setExecutableDuringCompilation(ExecutableBase*); ExecutableBase* executable(); void setStub(Ref&& newStub) { clearStub(); m_stub = WTFMove(newStub); } void clearStub(); PolymorphicCallStubRoutine* stub() { return m_stub.get(); } void setSlowStub(Ref&& newSlowStub) { m_slowStub = WTFMove(newSlowStub); } void clearSlowStub() { m_slowStub = nullptr; } JITStubRoutine* slowStub() { return m_slowStub.get(); } bool seenOnce() { return m_hasSeenShouldRepatch; } void clearSeen() { m_hasSeenShouldRepatch = false; } void setSeen() { m_hasSeenShouldRepatch = true; } bool hasSeenClosure() { return m_hasSeenClosure; } void setHasSeenClosure() { m_hasSeenClosure = true; } bool clearedByGC() { return m_clearedByGC; } void setCallType(CallType callType) { m_callType = callType; } CallType callType() { return static_cast(m_callType); } uint32_t* addressOfMaxNumArguments() { return &m_maxNumArguments; } uint32_t maxNumArguments() { return m_maxNumArguments; } void setMaxNumArguments(unsigned); static ptrdiff_t offsetOfSlowPathCount() { return OBJECT_OFFSETOF(CallLinkInfo, m_slowPathCount); } void setCalleeGPR(unsigned calleeGPR) { m_calleeGPR = calleeGPR; } unsigned calleeGPR() { return m_calleeGPR; } uint32_t slowPathCount() { return m_slowPathCount; } void setCodeOrigin(CodeOrigin codeOrigin) { m_codeOrigin = codeOrigin; } CodeOrigin codeOrigin() { return m_codeOrigin; } void visitWeak(VM&); void setFrameShuffleData(const CallFrameShuffleData&); const CallFrameShuffleData* frameShuffleData() { return m_frameShuffleData.get(); } private: CodeLocationLabel m_callReturnLocationOrPatchableJump; CodeLocationLabel m_hotPathBeginOrSlowPathStart; CodeLocationNearCall m_hotPathOther; WriteBarrier m_calleeOrCodeBlock; WriteBarrier m_lastSeenCalleeOrExecutable; RefPtr m_stub; RefPtr m_slowStub; std::unique_ptr m_frameShuffleData; bool m_hasSeenShouldRepatch : 1; bool m_hasSeenClosure : 1; bool m_clearedByGC : 1; bool m_allowStubs : 1; bool m_isLinked : 1; unsigned m_callType : 4; // CallType unsigned m_calleeGPR : 8; uint32_t m_maxNumArguments; // For varargs: the profiled maximum number of arguments. For direct: the number of stack slots allocated for arguments. uint32_t m_slowPathCount; CodeOrigin m_codeOrigin; }; inline CodeOrigin getCallLinkInfoCodeOrigin(CallLinkInfo& callLinkInfo) { return callLinkInfo.codeOrigin(); } typedef HashMap CallLinkInfoMap; #else // ENABLE(JIT) typedef HashMap CallLinkInfoMap; #endif // ENABLE(JIT) } // namespace JSC