blob: 8a77fc468bf397adbb52b973e25bcdf854dd78a9 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#pragma once
#include "CallMode.h"
#include "CodeLocation.h"
#include "CodeSpecializationKind.h"
#include "PolymorphicCallStubRoutine.h"
#include "WriteBarrier.h"
#include <wtf/SentinelLinkedList.h>
namespace JSC {
#if ENABLE(JIT)
class FunctionCodeBlock;
class JSFunction;
enum OpcodeID : unsigned;
struct CallFrameShuffleData;
class CallLinkInfo : public BasicRawSentinelNode<CallLinkInfo> {
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<CallType>(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<CallType>(m_callType));
}
bool isDirect()
{
return isDirect(static_cast<CallType>(m_callType));
}
bool isTailCall() const
{
return callMode() == CallMode::Tail;
}
NearCallMode nearCallMode() const
{
return isTailCall() ? Tail : Regular;
}
bool isVarargs() const
{
return isVarargsCallType(static_cast<CallType>(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<PolymorphicCallStubRoutine>&& newStub)
{
clearStub();
m_stub = WTFMove(newStub);
}
void clearStub();
PolymorphicCallStubRoutine* stub()
{
return m_stub.get();
}
void setSlowStub(Ref<JITStubRoutine>&& 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<CallType>(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<JSCell> m_calleeOrCodeBlock;
WriteBarrier<JSCell> m_lastSeenCalleeOrExecutable;
RefPtr<PolymorphicCallStubRoutine> m_stub;
RefPtr<JITStubRoutine> m_slowStub;
std::unique_ptr<CallFrameShuffleData> 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<CodeOrigin, CallLinkInfo*, CodeOriginApproximateHash> CallLinkInfoMap;
#else // ENABLE(JIT)
typedef HashMap<int, void*> CallLinkInfoMap;
#endif // ENABLE(JIT)
} // namespace JSC